Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts.

Motivation

A variety of different sources contribute different types of pollutants to what we call air pollution. Some sources are natural while others are anthropogenic (human derived):

Major types of air pollutants

  1. Gaseous - Carbon Monoxide (CO), Ozone (O3), Nitrogen Oxides(NO, NO2), Sulpher Dioxide (SO2)
  2. Particulate - small liquids and solids suspended in the air (includes lead- can include certain types of dust)
  3. Dust - small solids (larger than particulates) that can be suspended in the air for some time but eventually settle
  4. Biological - pollen, bacteria, viruses, mold spores

See [here])http://www.redlogenv.com/worker-safety/part-1-dust-and-particulate-matter) for more detail on the types of pollutants in the air.

Particulate pollution

Air pollution particulates are generally described by their size.

There are 3 major categories:

  1. Large Coarse Particulate Mater - has diameter of >10 micrometers (10 µm)

  2. Coarse Particulate Mater (called PM10-2.5) - has diameter of between 2.5 µm and 10 µm

  3. Fine Particulate Mater (called PM2.5) - has diameter of < 2.5 µm

PM10 includes any particulate mater <10 µm (both coarse and fine particulate mater)

Here you can see how these sizes compare with a human hair:

source

The following plot and table show the relative sizes of these different pollutants in micrometers(µm):

source

This table shows how deeply some of the smaller fine particles can penetrate within the human body:

Negative Impact of Particulate Exposure on Health

Exposure to air pollution is associated with higher rates of mortality in older adults and is known to be a risk factor for many diseases and conditions including but not limited to:

  1. Asthma - fine particle exposure (PM2.5) was found to be associated with higher rates of asthma in children
  2. Inflammation in type 1 diabetes - fine particle exposure (PM2.5) from traffic-related air pollution was associated with increased measures of inflammatory markers in youths with type 1 diabetes
  3. Lung function and emphysema - higher concentrations of ozone (O3), nitrogen oxides (NOx), black carbon, and fine particle exposure PM2.5 , at study baseline were significantly associated with greater increases in percent emphysema per 10 years
  4. Low birthweight - fine particle exposure(PM2.5) was associated with lower birth weight in full-term live births
  5. Viral Infection - higher rates of infection and increased severity of infection are associated with higher exposures to pollution levels including fine particle exposure (PM2.5)

See this review article for more information about sources of air pollution and the influence of air pollution on health.

Sparse Monitoring is Problematic for Public Health

Historically epidemiological studies would assess the influence of air pollution on health outcomes by relying on a number of monitors located around the country. However as can be seen in the following figure, these monitors remain to be relatively sparse in certain regions of the country. Furthermore, dramatic differences in pollution rates can be seen even within the same city.

source

This lack of granularity in air pollution monitoring has hindered our ability to discern the full impact of air pollution on health and to identify at-risk locations.

Machine Learning Offers a Solution

An article published in the Environmental Health journal dealt with this issue by using data about population density, road density, among other features to model or predict air pollution levels at a more localized scale using machine learning methods.

Yanosky, J. D. et al. Spatio-temporal modeling of particulate air pollution in the conterminous United States using geographic and meteorological predictors. Environ Health 13, 63 (2014).

The authors of this article state that:

“Exposure to atmospheric particulate matter (PM) remains an important public health concern, although it remains difficult to quantify accurately across large geographic areas with sufficiently high spatial resolution. Recent epidemiologic analyses have demonstrated the importance of spatially- and temporally-resolved exposure estimates, which show larger PM-mediated health effects as compared to nearest monitor or county-specific ambient concentrations.”

The article above explains that machine learning methods can be used to predict air pollution levels when traditional monitoring systems are not available in a particular area or when there is not enough spatial granularity with current monitoring systems. We will use similar methods to predict annual air pollution levels spatially within the US.

Main Questions

Our main question:

  1. Can we predict annual average air pollution concentrations at the granularity of zip code regional levels using predictors such as data about population density, urbanization, road density, as well as, satellite pollution data and chemical modeling data?

Learning Objectives

In this case study, we will walk you through importing data from CSV files and performing machine learning methods to predict our outcome variable of interest (in this case annual fine particle air pollution estimates). We will especially focus on using packages and functions from the Tidyverse, and more specifically the tidymodels package/ecosystem primarily developed and maintained by Max Kuhn and Davis Vaughan. This package loads more modeling related packages like rsample, recipes, parsnip, yardstick, and dials. We will also briefly cover the workflows and tune packages. The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R especially efficient.

We will begin by loading the packages that we will need:

Package Use
here to easily load and save data
readr to import the CSV file data
dplyr to view/arrange/filter/select/compare specific subsets of the data
skimr to get an overview of data
summarytools to get an overview of data in a different style
magrittr to use the %<>% pipping operator
corrplot to make large correlation plots
ggcorrplot also to make large correlation plots
GGally to make smaller correlation plots
rsample to split the data into testing and training sets and to split the training set for cross-validation
recipes to pre-process data for modeling in a tidy and reproducible way and to extract pre-processed data (major functions are recipe() , prep() and various transformation step_*() functions, as well as juice() - extracts final preprocessed training data and bake() - applies recipe steps to testing data). See here for more info.
parsnip an interface to create models (major functions are fit(), set_engine())
yardstick to evaluate the performance of models
broom to get tidy output for our model fit and performance
ggplot2 to make visualizations with multiple layers
dials to specify hyper-parameter tuning
tune to perform cross validation, tune hyper-parameters, and get performance metrics
workflows to create modeling workflow to streamline the modeling process
vip to create variable importance plots
randomForest to perform the random forest analysis
stringr to manipulate the text the map data
tidyr to separate data within a column into multiple columns
rnaturalearth to get the geometry data for the earth to plot the US
maps to get map database data about counties to draw them on our US map
sf to convert the map data into a data frame
lwgeom to use the sf function to convert the map geographical data
rgeos to use geometry data
cowplot to allow plots to be combined

The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.

Context

The State of Global Air is a report released every year to communicate the impact of air pollution on public health.

The State of Global Air 2019 report which uses data from 2017 stated that:

Air pollution is the fifth leading risk factor for mortality worldwide. It is responsible for more deaths than many better-known risk factors such as malnutrition, alcohol use, and physical inactivity. Each year, more people die from air pollution–related disease than from road traffic injuries or malaria.

The report also stated that:

In 2017, air pollution is estimated to have contributed to close to 5 million deaths globally — nearly 1 in every 10 deaths.

##### [source]

The State of Global Air 2018 report using data from 2016 which separated different types of air pollution, found that particulate pollution was particularly associated with mortality.

The 2019 report shows that the highest levels of fine particulate pollution occurs in Africa and Asia and that:

More than 90% of people worldwide live in areas exceeding the World Health Organization (WHO) Guideline for healthy air. More than half live in areas that do not even meet WHO’s least-stringent air quality target.

Looking at the US specifically, air pollution levels are generally improving. The US Environmental Protection Agency (EPA) also releases a report about air pollution levels called Our Nation’s Air.

[source]

However, air pollution continues to contribute to health risk for Americans, in particular in regions with higher than national average rates of pollution that actually at time exceed the world health organization’s recommended level. Thus it is necessary to obtain high spatial granularity in estimates of air pollution in order to identify locations where populations are experiencing harmful levels of exposure.

You can see that current air quality conditions at this website and you will notice variation across different cities.

Here were the conditions in Topeka Kansas when this was written:

It reports particulate values using what is called the Air Quality Index scale (AQI), this calculator indicates that 114 AQI is equivalent to 40.7 ug/m3 and is considered unhealthy for sensitive individuals. Thus some areas very much exceed the World Health Organization (WHO) annual exposure guideline (10 ug/m3) at certain times and this may adversely affect the health of people living in these locations.

Furthermore, adverse health effects have been associated with populations experiencing higher pollution exposure despite the levels being below suggested guidelines. Secondly, it appears that the composition of the particulate mater and the influence of other demographic factors may make specific populations more at risk for adverse health effects due to air pollution. See this article for more details.

The monitor data that we will use in this case study comes from a system of monitors in which roughly 90% are located within cities. Thus there is an equity issue in terms of capturing the air pollution levels of more rural areas. Therefore, to get a better sense of the pollution exposures for the individuals living in these areas, methods like machine learning can be very useful to estimate air pollution levels in areas with little to no monitoring.

Indeed, machine learning methods are in fact used to be able to estimate air pollution in these low monitoring areas so that we can make a map like this where we have annual estimates for all of the contiguous US:

[source]

This is what we aim to achieve in this case study.

Limitations

There are some important considerations regarding this data analysis to keep in mind:

  1. The data in our analysis does not include information about the composition of particulate mater. Different types of particulates may be more benign or deleterious for health outcomes.

  2. Outdoor pollution levels are not necessarily an indication of of individual exposures. People spend differing amounts of time indoors and outdoors and are exposed to different pollution levels indoors. People are now developing personal monitoring systems to track air pollution levels on the personal level.

Our analysis will use annual mean estimates, however pollution levels can vary greatly by season, day and even hour. There are data sources that have finer levels of temporal data, however we are interested in long term exposures, as these appear to be the most influential for health outcomes, so we chose to use annual level data.

What are the data?

In Machine Learning for prediction, there are two main types of variables:

  1. Outcome variable
  2. Predictor variables

The outcome variable is what are trying to predict. In building our model we actually have the outcome variable data, but we want to see how well our predictor variables can explain the variation in our outcome data. This gives us a sense of how well we can use the predictor variable data to predict our outcome variable levels when we in fact do not have data about the outcome.

As a simpler example, imagine that we have data about the sales and characteristics of cars from last year and we want to predict which cars might sell well this year. We do not have the sales data yet for this year, but we do know the characteristics of our cars for this year. We can use a model of the characteristics that explained sales last year to estimate what cars might sell well this year. In this case, our outcome variable is the sale performance of the cars, while the different characteristics of the cars make up our predictor or explanatory variables.

In this case study, we will evaluate air pollution monitor data of fine particulate mater (PM2.5) in the contiguous US from 2008, as well as data about population density, road density, urbanization levels, and NASA satellite data to develop models to predict localized air pollution levels.

The monitor data will be our outcome variable. We want to determine if we can predict air pollution levels based on other types of data, like road density and population density to see if we can use these data to predict air pollution in areas where there are no monitors.

Our outcome variable

The monitor data that we will be using comes from gravimetric monitors operated by the US Enivornmental Protection Agency (EPA). These monitors use a filtration system to specifically capture fine particulate matter. The weight of this matter is manually measured daily or weekly. See here for the EPA standard operating procedure for PM gravimetric analysis in 2008.

source

Here is an image of what the gravimetric monitors look like:

Gravimetric analysis is also used for emission testing. The same idea applies: a fresh filter is applied and the desired amount of time passes, then the filter is removed and weighed.

There are other monitoring systems that can provide hourly measurements, but we will not be using data from these monitors in our analysis. Gravimetric analysis is considered to be among the most accurate methods.

In our csv, the value column indicates the PM2.5 monitor average for 2008 in mass of fine particles/volume of air for 876 gravimetric monitors. The units are micro grams of fine particulate mater (PM) that is less than 2.5 micrometers in diameter per cubic meter of air - mass concentration (ug/m3). Recall the the WHO exposure guideline is < 10 ug/m3 on average annually for PM2.5.

Our predictor variables

There are 48 predictor variables with values for each of the 876 monitors included in our outcome variable. The data comes from the US Enivornmental Protection Agency (EPA), the National Aeronautics and Space Administration (NASA), the US Census, and the National Center for Health Statistics (NCHS).

Click here to see a table about the variables

Variable Details
id Monitor number
– the county number is indicated before the decimal
– the monitor number is indicated after the decimal
Example: 1073.0023 is Jefferson county (1073) and .0023 one of 8 monitors
fips Federal information processing standard number for the county where the monitor is located
– 5 digit id code for counties (zero is often the first value and sometimes is not shown)
– the first 2 numbers indicate the state
– the last three numbers indicate the county
Example: Alabama’s state code is 01 because it is first alphabetically
(note: Alaska and Hawaii are not included because they are not part of the contiguous US)
Lat Latitude of the monitor in degrees
Lon Longitude of the monitor in degrees
state State where the monitor is located
county County where the monitor is located
city City where the monitor is located
CMAQ Estimated values of air pollution from a computational model called Community Multiscale Air Quality (CMAQ)
– A monitoring system that simulates the physics of the atmosphere using chemistry and weather data to predict the air pollution
Does not use any of the PM2.5 gravimetric monitoring data. (There is a version that does use the gravimetric monitoring data, but not this one!)
– Data from the EPA
zcta Zip Code Tabulation Area where the monitor is located
– Postal Zip codes are converted into “generalized areal representations” that are non-overlapping
– Data from the 2010 Census
zcta_area Land area of the zip code area in meters squared
– Data from the 2010 Census
zcta_pop Population in the zip code area
– Data from the 2010 Census
imp_a500 Impervious surface measure
– Within a circle with a radius of 500 meters around the monitor
– Impervious surface are roads, concrete, parking lots, buildings
– This is a measure of development
imp_a1000 Impervious surface measure
– Within a circle with a radius of 1000 meters around the monitor
imp_a5000 Impervious surface measure
– Within a circle with a radius of 5000 meters around the monitor
imp_a10000 Impervious surface measure
– Within a circle with a radius of 10000 meters around the monitor
imp_a15000 Impervious surface measure
– Within a circle with a radius of 15000 meters around the monitor
county_area Land area of the county of the monitor in meters squared
county_pop Population of the county of the monitor
Log_dist_to_prisec Log (Natural log) distance to a primary or secondary road from the monitor
– Highway or major road
log_pri_length_5000 Count of primary road length in meters in a circle with a radius of 5000 meters around the monitor (Natural log)
– Highways only
log_pri_length_10000 Count of primary road length in meters in a circle with a radius of 10000 meters around the monitor (Natural log)
– Highways only
log_pri_length_15000 Count of primary road length in meters in a circle with a radius of 15000 meters around the monitor (Natural log)
– Highways only
log_pri_length_25000 Count of primary road length in meters in a circle with a radius of 25000 meters around the monitor (Natural log)
– Highways only
log_prisec_length_500 Count of primary and secondary road length in meters in a circle with a radius of 500 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_1000 Count of primary and secondary road length in meters in a circle with a radius of 1000 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_5000 Count of primary and secondary road length in meters in a circle with a radius of 5000 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_10000 Count of primary and secondary road length in meters in a circle with a radius of 10000 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_15000 Count of primary and secondary road length in meters in a circle with a radius of 15000 meters around the monitor (Natural log)
– Highway and secondary roads
log_prisec_length_25000 Count of primary and secondary road length in meters in a circle with a radius of 25000 meters around the monitor (Natural log)
– Highway and secondary roads
log_nei_2008_pm25_sum_10000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 10000 meters of distance around the monitor (Natural log)
log_nei_2008_pm25_sum_15000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 15000 meters of distance around the monitor (Natural log)
log_nei_2008_pm25_sum_25000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 25000 meters of distance around the monitor (Natural log)
log_nei_2008_pm10_sum_10000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 10000 meters of distance around the monitor (Natural log)
log_nei_2008_pm10_sum_15000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 15000 meters of distance around the monitor (Natural log)
log_nei_2008_pm10_sum_25000 Tons of emissions from major sources data base (annual data) sum of all sources within a circle with a radius of 25000 meters of distance around the monitor (Natural log)
popdens_county Population density (number of people per kilometer squared area of the county)
popdens_zcta Population density (number of people per kilometer squared area of zcta)
nohs Percentage of people in zcta area where the monitor is that do not have a high school degree
– Data from the Census
somehs Percentage of people in zcta area where the monitor whose highest formal educational attainment was some high school education
– Data from the Census
hs Percentage of people in zcta area where the monitor whose highest formal educational attainment was completing a high school degree
– Data from the Census
somecollege Percentage of people in zcta area where the monitor whose highest formal educational attainment was completing some college education
– Data from the Census
associate Percentage of people in zcta area where the monitor whose highest formal educational attainment was completing an associate degree
– Data from the Census
bachelor Percentage of people in zcta area where the monitor whose highest formal educational attainment was a bachelor’s degree
– Data from the Census
grad Percentage of people in zcta area where the monitor whose highest formal educational attainment was a graduate degree
– Data from the Census
pov Percentage of people in zcta area where the monitor is that lived in poverty in 2008 - or would it have been 2007 guidelines??https://aspe.hhs.gov/2007-hhs-poverty-guidelines
– Data from the Census
hs_orless Percentage of people in zcta area where the monitor whose highest formal educational attainment was a high school degree or less (sum of nohs, somehs, and hs)
urc2013 2013 Urban-rural classification of the county where the monitor is located
– 6 category variable - 1 is totally urban 6 is completely rural
– Data from the National Center for Health Statistics](https://www.cdc.gov/nchs/index.htm){target="_blank"}
urc2006 2006 Urban-rural classification of the county where the monitor is located
– 6 category variable - 1 is totally urban 6 is completely rural
– Data from the National Center for Health Statistics
aod Aerosol Optical Depth measurement from a NASA satellite
– based on the diffraction of a laser
– used as a proxy of particulate pollution
– unit-less - higher value indicates more pollution
– Data from NASA

Many of these predictor variables have to do with the circular area around the monitor called the “buffer”. These are illustrated in the following figure:

Data Import

We have one CSV file that contains both our single outcome variable and all of our predictor variables.

Let’s import our data into R now so that we can explore the data further. We will call our data object pm for particulate matter.

Data Exploration and Wrangling

The first step in performing a machine learning analysis is to explore the data to better understand the variables included in the data, as we may learn about important details about the data that we should keep in mind as we try to predict our outcome variable.

First let’s just get a general sense of our data. We can do that using the glimpse() function of the dplyr package (it is also in the tibble package).

We will also use the %>% pipe which can be used to define the input for later sequential steps. This will make more sense when we have multiple sequential steps using the same data object. To use the pipe notation we need to install and load dplyr as well.

For example here we will first grab the pm data object, then we use the glimpse() function on it based on the pipe notation.

Rows: 876
Columns: 50
$ id                          <dbl> 1003.001, 1027.000, 1033.100, 1049.100, 1…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 11.659091…
$ fips                        <dbl> 1003, 1027, 1033, 1049, 1055, 1069, 1073,…
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 34.28763, 3…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85.9683…
$ state                       <chr> "Alabama", "Alabama", "Alabama", "Alabama…
$ county                      <chr> "Baldwin", "Clay", "Colbert", "DeKalb", "…
$ city                        <chr> "Fairhope", "Ashland", "Muscle Shoals", "…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 8.534772, 9…
$ zcta                        <dbl> 36532, 36251, 35660, 35962, 35901, 36303,…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 203836235…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 8300, 20045, 30217, 90…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038, 5.78…
$ imp_a1000                   <dbl> 1.4096021, 0.8531574, 11.1448962, 3.86764…
$ imp_a5000                   <dbl> 3.3360118, 0.9851479, 15.1786154, 1.23114…
$ imp_a10000                  <dbl> 1.9879187, 0.5208189, 9.7253870, 1.031646…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 0.973044…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, 20126…
$ county_pop                  <dbl> 182265, 13932, 54428, 71109, 104430, 1015…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 3.721489, 5…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 8.517193, 9…
$ log_pri_length_10000        <dbl> 9.210340, 9.210340, 9.274303, 10.409411, …
$ log_pri_length_15000        <dbl> 9.630228, 9.615805, 9.658899, 11.173626, …
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 11.90959, 1…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 7.310155, 8…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 8.585843, 9…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 10.21420…
$ log_prisec_length_10000     <dbl> 11.88680, 11.40554, 12.84066, 11.50894, 1…
$ log_prisec_length_15000     <dbl> 12.205723, 12.042963, 13.282656, 12.35366…
$ log_prisec_length_25000     <dbl> 13.41395, 12.79980, 13.79973, 13.55979, 1…
$ log_nei_2008_pm25_sum_10000 <dbl> 0.318035438, 3.218632928, 6.573127301, 0.…
$ log_nei_2008_pm25_sum_15000 <dbl> 1.967358961, 3.218632928, 6.581917457, 3.…
$ log_nei_2008_pm25_sum_25000 <dbl> 5.067308, 3.218633, 6.875900, 4.887665, 4…
$ log_nei_2008_pm10_sum_10000 <dbl> 1.35588511, 3.31111648, 6.69187313, 0.000…
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, 3.350…
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 5.171920, 4…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 35.330814…
$ popdens_zcta                <dbl> 145.716431, 13.639555, 540.887040, 40.718…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 14.3, 4.3, 5.8, 7.1, 2.7,…
$ somehs                      <dbl> 4.9, 19.1, 15.8, 16.7, 13.3, 11.6, 17.1, …
$ hs                          <dbl> 25.1, 33.9, 30.6, 35.0, 27.8, 29.8, 37.2,…
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 14.9, 29.2, 21.4, 23.5,…
$ associate                   <dbl> 8.2, 8.0, 7.6, 5.5, 10.1, 7.9, 7.3, 8.0, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 7.9, 10.0, 13.7, 5.9, 17…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.8, 5.4, 9.8, 2.0, 8.7, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 13.8, 8.8, 15.6, 25.5, 7…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 66.0, 45.4, 47.2, 61.4,…
$ urc2013                     <dbl> 4, 6, 4, 6, 4, 4, 1, 1, 1, 1, 1, 1, 1, 2,…
$ urc2006                     <dbl> 5, 6, 4, 5, 4, 4, 1, 1, 1, 1, 1, 1, 1, 2,…
$ aod                         <dbl> 37.36364, 34.81818, 36.00000, 33.08333, 4…

We can see that there are 876 monitors and that we have 50 total variables - one of which is the outcome. In this case our outcome variable is called value.

Notice that some of the variables that we would think of as factors (categorical) are currently of class double as indicated by the <dbl> just to the right of the column names/variable names in the glimpse() output. For example the monitor ID (id), the Federal Information Processing Standard number for the county where the monitor was located (fips), as well as the zcta

Let’s convert these variables into factors. We can do this using the mutate_at() function of the dplyr package and the as.factor() base function.

In this case we are also using the magrittr assignment pipe or double pipe that looks like this %<>% of the magrittr package. This allows us use the pm data as input but also reassign the output to the same data object name.

Rows: 876
Columns: 50
$ id                          <fct> 1003.001, 1027.0001, 1033.1002, 1049.1003…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 11.659091…
$ fips                        <fct> 1003, 1027, 1033, 1049, 1055, 1069, 1073,…
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 34.28763, 3…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85.9683…
$ state                       <chr> "Alabama", "Alabama", "Alabama", "Alabama…
$ county                      <chr> "Baldwin", "Clay", "Colbert", "DeKalb", "…
$ city                        <chr> "Fairhope", "Ashland", "Muscle Shoals", "…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 8.534772, 9…
$ zcta                        <fct> 36532, 36251, 35660, 35962, 35901, 36303,…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 203836235…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 8300, 20045, 30217, 90…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038, 5.78…
$ imp_a1000                   <dbl> 1.4096021, 0.8531574, 11.1448962, 3.86764…
$ imp_a5000                   <dbl> 3.3360118, 0.9851479, 15.1786154, 1.23114…
$ imp_a10000                  <dbl> 1.9879187, 0.5208189, 9.7253870, 1.031646…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 0.973044…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, 20126…
$ county_pop                  <dbl> 182265, 13932, 54428, 71109, 104430, 1015…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 3.721489, 5…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 8.517193, 9…
$ log_pri_length_10000        <dbl> 9.210340, 9.210340, 9.274303, 10.409411, …
$ log_pri_length_15000        <dbl> 9.630228, 9.615805, 9.658899, 11.173626, …
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 11.90959, 1…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 7.310155, 8…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 8.585843, 9…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 10.21420…
$ log_prisec_length_10000     <dbl> 11.88680, 11.40554, 12.84066, 11.50894, 1…
$ log_prisec_length_15000     <dbl> 12.205723, 12.042963, 13.282656, 12.35366…
$ log_prisec_length_25000     <dbl> 13.41395, 12.79980, 13.79973, 13.55979, 1…
$ log_nei_2008_pm25_sum_10000 <dbl> 0.318035438, 3.218632928, 6.573127301, 0.…
$ log_nei_2008_pm25_sum_15000 <dbl> 1.967358961, 3.218632928, 6.581917457, 3.…
$ log_nei_2008_pm25_sum_25000 <dbl> 5.067308, 3.218633, 6.875900, 4.887665, 4…
$ log_nei_2008_pm10_sum_10000 <dbl> 1.35588511, 3.31111648, 6.69187313, 0.000…
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, 3.350…
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 5.171920, 4…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 35.330814…
$ popdens_zcta                <dbl> 145.716431, 13.639555, 540.887040, 40.718…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 14.3, 4.3, 5.8, 7.1, 2.7,…
$ somehs                      <dbl> 4.9, 19.1, 15.8, 16.7, 13.3, 11.6, 17.1, …
$ hs                          <dbl> 25.1, 33.9, 30.6, 35.0, 27.8, 29.8, 37.2,…
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 14.9, 29.2, 21.4, 23.5,…
$ associate                   <dbl> 8.2, 8.0, 7.6, 5.5, 10.1, 7.9, 7.3, 8.0, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 7.9, 10.0, 13.7, 5.9, 17…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.8, 5.4, 9.8, 2.0, 8.7, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 13.8, 8.8, 15.6, 25.5, 7…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 66.0, 45.4, 47.2, 61.4,…
$ urc2013                     <dbl> 4, 6, 4, 6, 4, 4, 1, 1, 1, 1, 1, 1, 1, 2,…
$ urc2006                     <dbl> 5, 6, 4, 5, 4, 4, 1, 1, 1, 1, 1, 1, 1, 2,…
$ aod                         <dbl> 37.36364, 34.81818, 36.00000, 33.08333, 4…

Great! Now we can see that these variables are now factors as indicated by <fct> after the variable name.

Packages to get a sense of the data

The skim() function of the skimr package is also really helpful for getting a general sense of your data.

Data summary
Name pm
Number of rows 876
Number of columns 50
_______________________
Column type frequency:
character 3
factor 3
numeric 44
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
state 0 1 4 20 0 49 0
county 0 1 3 20 0 471 0
city 0 1 4 48 0 607 0

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
id 0 1 FALSE 876 100: 1, 102: 1, 103: 1, 104: 1
fips 0 1 FALSE 569 170: 12, 603: 10, 261: 9, 107: 8
zcta 0 1 FALSE 842 475: 3, 110: 2, 160: 2, 290: 2

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
value 0 1 10.81 2.580000e+00 3.02 9.27 11.15 12.37 2.316000e+01 ▂▆▇▁▁
lat 0 1 38.48 4.620000e+00 25.47 35.03 39.30 41.66 4.840000e+01 ▁▃▅▇▂
lon 0 1 -91.74 1.496000e+01 -124.18 -99.16 -87.47 -80.69 -6.804000e+01 ▃▂▃▇▃
CMAQ 0 1 8.41 2.970000e+00 1.63 6.53 8.62 10.24 2.313000e+01 ▃▇▃▁▁
zcta_area 0 1 183173481.91 5.425989e+08 15459.00 14204601.75 37653560.50 160041508.25 8.164821e+09 ▇▁▁▁▁
zcta_pop 0 1 24227.58 1.777216e+04 0.00 9797.00 22014.00 35004.75 9.539700e+04 ▇▇▃▁▁
imp_a500 0 1 24.72 1.934000e+01 0.00 3.70 25.12 40.22 6.961000e+01 ▇▅▆▃▂
imp_a1000 0 1 24.26 1.802000e+01 0.00 5.32 24.53 38.59 6.750000e+01 ▇▅▆▃▁
imp_a5000 0 1 19.93 1.472000e+01 0.05 6.79 19.07 30.11 7.460000e+01 ▇▆▃▁▁
imp_a10000 0 1 15.82 1.381000e+01 0.09 4.54 12.36 24.17 7.209000e+01 ▇▃▂▁▁
imp_a15000 0 1 13.43 1.312000e+01 0.11 3.24 9.67 20.55 7.110000e+01 ▇▃▁▁▁
county_area 0 1 3768701992.12 6.212830e+09 33703512.00 1116536297.50 1690826566.50 2878192209.00 5.194723e+10 ▇▁▁▁▁
county_pop 0 1 687298.44 1.293489e+06 783.00 100948.00 280730.50 743159.00 9.818605e+06 ▇▁▁▁▁
log_dist_to_prisec 0 1 6.19 1.410000e+00 -1.46 5.43 6.36 7.15 1.045000e+01 ▁▁▃▇▁
log_pri_length_5000 0 1 9.82 1.080000e+00 8.52 8.52 10.05 10.73 1.205000e+01 ▇▂▆▅▂
log_pri_length_10000 0 1 10.92 1.130000e+00 9.21 9.80 11.17 11.83 1.302000e+01 ▇▂▇▇▃
log_pri_length_15000 0 1 11.50 1.150000e+00 9.62 10.87 11.72 12.40 1.359000e+01 ▆▂▇▇▃
log_pri_length_25000 0 1 12.24 1.100000e+00 10.13 11.69 12.46 13.05 1.436000e+01 ▅▃▇▇▃
log_prisec_length_500 0 1 6.99 9.500000e-01 6.21 6.21 6.21 7.82 9.400000e+00 ▇▁▂▂▁
log_prisec_length_1000 0 1 8.56 7.900000e-01 7.60 7.60 8.66 9.20 1.047000e+01 ▇▅▆▃▁
log_prisec_length_5000 0 1 11.28 7.800000e-01 8.52 10.91 11.42 11.83 1.278000e+01 ▁▁▃▇▃
log_prisec_length_10000 0 1 12.41 7.300000e-01 9.21 11.99 12.53 12.94 1.385000e+01 ▁▁▃▇▅
log_prisec_length_15000 0 1 13.03 7.200000e-01 9.62 12.59 13.13 13.57 1.441000e+01 ▁▁▃▇▅
log_prisec_length_25000 0 1 13.82 7.000000e-01 10.13 13.38 13.92 14.35 1.523000e+01 ▁▁▃▇▆
log_nei_2008_pm25_sum_10000 0 1 3.97 2.350000e+00 0.00 2.15 4.29 5.69 9.120000e+00 ▆▅▇▆▂
log_nei_2008_pm25_sum_15000 0 1 4.72 2.250000e+00 0.00 3.47 5.00 6.35 9.420000e+00 ▃▃▇▇▂
log_nei_2008_pm25_sum_25000 0 1 5.67 2.110000e+00 0.00 4.66 5.91 7.28 9.650000e+00 ▂▂▇▇▃
log_nei_2008_pm10_sum_10000 0 1 4.35 2.320000e+00 0.00 2.69 4.62 6.07 9.340000e+00 ▅▅▇▇▂
log_nei_2008_pm10_sum_15000 0 1 5.10 2.180000e+00 0.00 3.87 5.39 6.72 9.710000e+00 ▂▃▇▇▂
log_nei_2008_pm10_sum_25000 0 1 6.07 2.010000e+00 0.00 5.10 6.37 7.52 9.880000e+00 ▁▂▆▇▃
popdens_county 0 1 551.76 1.711510e+03 0.26 40.77 156.67 510.81 2.682191e+04 ▇▁▁▁▁
popdens_zcta 0 1 1279.66 2.757490e+03 0.00 101.15 610.35 1382.52 3.041884e+04 ▇▁▁▁▁
nohs 0 1 6.99 7.210000e+00 0.00 2.70 5.10 8.80 1.000000e+02 ▇▁▁▁▁
somehs 0 1 10.17 6.200000e+00 0.00 5.90 9.40 13.90 7.220000e+01 ▇▂▁▁▁
hs 0 1 30.32 1.140000e+01 0.00 23.80 30.75 36.10 1.000000e+02 ▂▇▂▁▁
somecollege 0 1 21.58 8.600000e+00 0.00 17.50 21.30 24.70 1.000000e+02 ▆▇▁▁▁
associate 0 1 7.13 4.010000e+00 0.00 4.90 7.10 8.80 7.140000e+01 ▇▁▁▁▁
bachelor 0 1 14.90 9.710000e+00 0.00 8.80 12.95 19.22 1.000000e+02 ▇▂▁▁▁
grad 0 1 8.91 8.650000e+00 0.00 3.90 6.70 11.00 1.000000e+02 ▇▁▁▁▁
pov 0 1 14.95 1.133000e+01 0.00 6.50 12.10 21.22 6.590000e+01 ▇▅▂▁▁
hs_orless 0 1 47.48 1.675000e+01 0.00 37.92 48.65 59.10 1.000000e+02 ▁▃▇▃▁
urc2013 0 1 2.92 1.520000e+00 1.00 2.00 3.00 4.00 6.000000e+00 ▇▅▃▂▁
urc2006 0 1 2.97 1.520000e+00 1.00 2.00 3.00 4.00 6.000000e+00 ▇▅▃▂▁
aod 0 1 43.70 1.956000e+01 5.00 31.66 40.17 49.67 1.430000e+02 ▃▇▁▁▁

Notice how there is a column called n_missing about the number of values that are missing. It looks like our data is very complete and we do not have any missing data. This is also indicated by the complete_rate variable, which shows the ratio of completeness, in our case all variables have a value of 1 indicating they are fully complete.

The n_unqiue column shows us the number of unique values for each of our columns. We can see that there are 49 states represented in the data, and we know that the data should be of the contiguous states. Let’s take a look to see which states are included:

# A tibble: 49 x 1
   state               
   <chr>               
 1 Alabama             
 2 Arizona             
 3 Arkansas            
 4 California          
 5 Colorado            
 6 Connecticut         
 7 Delaware            
 8 District Of Columbia
 9 Florida             
10 Georgia             
11 Idaho               
12 Illinois            
13 Indiana             
14 Iowa                
15 Kansas              
16 Kentucky            
17 Louisiana           
18 Maine               
19 Maryland            
20 Massachusetts       
21 Michigan            
22 Minnesota           
23 Mississippi         
24 Missouri            
25 Montana             
26 Nebraska            
27 Nevada              
28 New Hampshire       
29 New Jersey          
30 New Mexico          
31 New York            
32 North Carolina      
33 North Dakota        
34 Ohio                
35 Oklahoma            
36 Oregon              
37 Pennsylvania        
38 Rhode Island        
39 South Carolina      
40 South Dakota        
41 Tennessee           
42 Texas               
43 Utah                
44 Vermont             
45 Virginia            
46 Washington          
47 West Virginia       
48 Wisconsin           
49 Wyoming             

Looks like “District of Columbia” is being included as a state. We can see that indeed Alaska and Hawaii are not included in the data.

Here is another method of looking at the data using the dfSummary() function of the summarytoolspackage. We need to copy and paste the output into the rmarkdown.

Click here to see the dfSummary table

Dimensions: 876 x 50
Duplicates: 0

No Variable Stats / Values Freqs (% of Valid) Graph Valid Missing
1 id
[factor]
1. 1003.001
2. 1027.0001
3. 1033.1002
4. 1049.1003
5. 1055.001
6. 1069.0003
7. 1073.0023
8. 1073.1005
9. 1073.1009
10. 1073.101
[ 866 others ]
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
866 (98.9%)
876
(100%)
0
(0%)
2 value
[numeric]
Mean (sd) : 10.8 (2.6)
min < med < max:
3 < 11.2 < 23.2
IQR (CV) : 3.1 (0.2)
875 distinct values 876
(100%)
0
(0%)
3 fips
[factor]
1. 1003
2. 1027
3. 1033
4. 1049
5. 1055
6. 1069
7. 1073
8. 1089
9. 1097
10. 1101
[ 559 others ]
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
8 ( 0.9%)
1 ( 0.1%)
2 ( 0.2%)
1 ( 0.1%)
858 (98.0%)
876
(100%)
0
(0%)
4 lat
[numeric]
Mean (sd) : 38.5 (4.6)
min < med < max:
25.5 < 39.3 < 48.4
IQR (CV) : 6.6 (0.1)
876 distinct values 876
(100%)
0
(0%)
5 lon
[numeric]
Mean (sd) : -91.7 (15)
min < med < max:
-124.2 < -87.5 < -68
IQR (CV) : 18.5 (-0.2)
876 distinct values 876
(100%)
0
(0%)
6 state
[character]
1. California
2. Ohio
3. Illinois
4. Indiana
5. North Carolina
6. Pennsylvania
7. Michigan
8. Florida
9. Georgia
10. Texas
[ 39 others ]
85 ( 9.7%)
44 ( 5.0%)
38 ( 4.3%)
36 ( 4.1%)
35 ( 4.0%)
32 ( 3.7%)
30 ( 3.4%)
29 ( 3.3%)
28 ( 3.2%)
27 ( 3.1%)
492 (56.2%)
876
(100%)
0
(0%)
7 county
[character]
1. Jefferson
2. Cook
3. Hamilton
4. Lake
5. Los Angeles
6. Wayne
7. Washington
8. Cuyahoga
9. Jackson
10. Madison
[ 461 others ]
18 ( 2.1%)
12 ( 1.4%)
11 ( 1.3%)
11 ( 1.3%)
10 ( 1.1%)
10 ( 1.1%)
9 ( 1.0%)
7 ( 0.8%)
7 ( 0.8%)
7 ( 0.8%)
774 (88.4%)
876
(100%)
0
(0%)
8 city
[character]
1. Not in a city
2. New York
3. Cleveland
4. Baltimore
5. Chicago
6. Detroit
7. Milwaukee
8. New Haven
9. Philadelphia
10. Springfield
[ 597 others ]
103 (11.8%)
9 ( 1.0%)
6 ( 0.7%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
5 ( 0.6%)
723 (82.5%)
876
(100%)
0
(0%)
9 CMAQ  | Me [numeric] an (sd) : 8.4 (3)  | 60 min < med < max:
1.6 < 8.6 < 23.1
IQR (CV) : 3.7 (0.4)
1 distinct values | ![ ](tmp/ds0109.png) | 87 6  | 0
(100%)
(0%)
10 zcta
[factor]
1. 1022
2. 1103
3. 1201
4. 1608
5. 1832
6. 1840
7. 1863
8. 1904
9. 2113
10. 2119
[ 832 others ]
1 ( 0.1%)
2 ( 0.2%)
1 ( 0.1%)
2 ( 0.2%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
1 ( 0.1%)
864 (98.6%)
876
(100%)
0
(0%)
11 zcta_area
[numeric]
Mean (sd) : 183173481.9 (542598878.5)
min < med < max:
15459 < 37653560.5 < 8164820625
IQR (CV) : 145836906.5 (3)
842 distinct values 876
(100%)
0
(0%)
12 zcta_pop
[numeric]
Mean (sd) : 24227.6 (17772.2)
min < med < max:
0 < 22014 < 95397
IQR (CV) : 25207.8 (0.7)
837 distinct values 876
(100%)
0
(0%)
13 imp_a500
[numeric]
Mean (sd) : 24.7 (19.3)
min < med < max:
0 < 25.1 < 69.6
IQR (CV) : 36.5 (0.8)
816 distinct values 876
(100%)
0
(0%)
14 imp_a1000
[numeric]
Mean (sd) : 24.3 (18)
min < med < max:
0 < 24.5 < 67.5
IQR (CV) : 33.3 (0.7)
860 distinct values 876
(100%)
0
(0%)
15 imp_a5000
[numeric]
Mean (sd) : 19.9 (14.7)
min < med < max:
0.1 < 19.1 < 74.6
IQR (CV) : 23.3 (0.7)
870 distinct values 876
(100%)
0
(0%)
16 imp_a10000
[numeric]
Mean (sd) : 15.8 (13.8)
min < med < max:
0.1 < 12.4 < 72.1
IQR (CV) : 19.6 (0.9)
870 distinct values 876
(100%)
0
(0%)
17 imp_a15000
[numeric]
Mean (sd) : 13.4 (13.1)
min < med < max:
0.1 < 9.7 < 71.1
IQR (CV) : 17.3 (1)
870 distinct values 876
(100%)
0
(0%)
18 county_area
[numeric]
Mean (sd) : 3768701992.1 (6212829553.6)
min < med < max:
33703512 < 1690826566.5 < 51947229509
IQR (CV) : 1761655911.5 (1.6)
564 distinct values 876
(100%)
0
(0%)
19 county_pop
[numeric]
Mean (sd) : 687298.4 (1293488.7)
min < med < max:
783 < 280730.5 < 9818605
IQR (CV) : 642211 (1.9)
564 distinct values 876
(100%)
0
(0%)
20 log_dist_to_prisec
[numeric]
Mean (sd) : 6.2 (1.4)
min < med < max:
-1.5 < 6.4 < 10.5
IQR (CV) : 1.7 (0.2)
870 distinct values 876
(100%)
0
(0%)
21 log_pri_length_5000
[numeric]
Mean (sd) : 9.8 (1.1)
min < med < max:
8.5 < 10.1 < 12
IQR (CV) : 2.2 (0.1)
586 distinct values 876
(100%)
0
(0%)
22 log_pri_length_10000
[numeric]
Mean (sd) : 10.9 (1.1)
min < med < max:
9.2 < 11.2 < 13
IQR (CV) : 2 (0.1)
687 distinct values 876
(100%)
0
(0%)
23 log_pri_length_15000
[numeric]
Mean (sd) : 11.5 (1.1)
min < med < max:
9.6 < 11.7 < 13.6
IQR (CV) : 1.5 (0.1)
726 distinct values 876
(100%)
0
(0%)
24 log_pri_length_25000
[numeric]
Mean (sd) : 12.2 (1.1)
min < med < max:
10.1 < 12.5 < 14.4
IQR (CV) : 1.4 (0.1)
787 distinct values 876
(100%)
0
(0%)
25 log_prisec_length_500
[numeric]
Mean (sd) : 7 (1)
min < med < max:
6.2 < 6.2 < 9.4
IQR (CV) : 1.6 (0.1)
382 distinct values 876
(100%)
0
(0%)
26 log_prisec_length_1000
[numeric]
Mean (sd) : 8.6 (0.8)
min < med < max:
7.6 < 8.7 < 10.5
IQR (CV) : 1.6 (0.1)
591 distinct values 876
(100%)
0
(0%)
27 log_prisec_length_5000
[numeric]
Mean (sd) : 11.3 (0.8)
min < med < max:
8.5 < 11.4 < 12.8
IQR (CV) : 0.9 (0.1)
852 distinct values 876
(100%)
0
(0%)
28 log_prisec_length_10000
[numeric]
Mean (sd) : 12.4 (0.7)
min < med < max:
9.2 < 12.5 < 13.8
IQR (CV) : 1 (0.1)
867 distinct values 876
(100%)
0
(0%)
29 log_prisec_length_15000
[numeric]
Mean (sd) : 13 (0.7)
min < med < max:
9.6 < 13.1 < 14.4
IQR (CV) : 1 (0.1)
869 distinct values 876
(100%)
0
(0%)
30 log_prisec_length_25000
[numeric]
Mean (sd) : 13.8 (0.7)
min < med < max:
10.1 < 13.9 < 15.2
IQR (CV) : 1 (0.1)
870 distinct values 876
(100%)
0
(0%)
31 log_nei_2008_pm25_sum_10000
[numeric]
Mean (sd) : 4 (2.4)
min < med < max:
0 < 4.3 < 9.1
IQR (CV) : 3.5 (0.6)
828 distinct values 876
(100%)
0
(0%)
32 log_nei_2008_pm25_sum_15000
[numeric]
Mean (sd) : 4.7 (2.2)
min < med < max:
0 < 5 < 9.4
IQR (CV) : 2.9 (0.5)
855 distinct values 876
(100%)
0
(0%)
33 log_nei_2008_pm25_sum_25000
[numeric]
Mean (sd) : 5.7 (2.1)
min < med < max:
0 < 5.9 < 9.7
IQR (CV) : 2.6 (0.4)
860 distinct values 876
(100%)
0
(0%)
34 log_nei_2008_pm10_sum_10000
[numeric]
Mean (sd) : 4.3 (2.3)
min < med < max:
0 < 4.6 < 9.3
IQR (CV) : 3.4 (0.5)
829 distinct values 876
(100%)
0
(0%)
35 log_nei_2008_pm10_sum_15000
[numeric]
Mean (sd) : 5.1 (2.2)
min < med < max:
0 < 5.4 < 9.7
IQR (CV) : 2.8 (0.4)
855 distinct values 876
(100%)
0
(0%)
36 log_nei_2008_pm10_sum_25000
[numeric]
Mean (sd) : 6.1 (2)
min < med < max:
0 < 6.4 < 9.9
IQR (CV) : 2.4 (0.3)
860 distinct values 876
(100%)
0
(0%)
37 popdens_county
[numeric]
Mean (sd) : 551.8 (1711.5)
min < med < max:
0.3 < 156.7 < 26821.9
IQR (CV) : 470 (3.1)
564 distinct values 876
(100%)
0
(0%)
38 popdens_zcta
[numeric]
Mean (sd) : 1279.7 (2757.5)
min < med < max:
0 < 610.3 < 30418.8
IQR (CV) : 1281.4 (2.2)
840 distinct values 876
(100%)
0
(0%)
39 nohs
[numeric]
Mean (sd) : 7 (7.2)
min < med < max:
0 < 5.1 < 100
IQR (CV) : 6.1 (1)
215 distinct values 876
(100%)
0
(0%)
40 somehs
[numeric]
Mean (sd) : 10.2 (6.2)
min < med < max:
0 < 9.4 < 72.2
IQR (CV) : 8 (0.6)
230 distinct values 876
(100%)
0
(0%)
41 hs
[numeric]
Mean (sd) : 30.3 (11.4)
min < med < max:
0 < 30.8 < 100
IQR (CV) : 12.3 (0.4)
347 distinct values 876
(100%)
0
(0%)
42 somecollege
[numeric]
Mean (sd) : 21.6 (8.6)
min < med < max:
0 < 21.3 < 100
IQR (CV) : 7.2 (0.4)
240 distinct values 876
(100%)
0
(0%)
43 associate
[numeric]
Mean (sd) : 7.1 (4)
min < med < max:
0 < 7.1 < 71.4
IQR (CV) : 3.9 (0.6)
157 distinct values 876
(100%)
0
(0%)
44 bachelor
[numeric]
Mean (sd) : 14.9 (9.7)
min < med < max:
0 < 12.9 < 100
IQR (CV) : 10.4 (0.7)
301 distinct values 876
(100%)
0
(0%)
45 grad
[numeric]
Mean (sd) : 8.9 (8.6)
min < med < max:
0 < 6.7 < 100
IQR (CV) : 7.1 (1)
245 distinct values 876
(100%)
0
(0%)
46 pov
[numeric]
Mean (sd) : 15 (11.3)
min < med < max:
0 < 12.1 < 65.9
IQR (CV) : 14.7 (0.8)
345 distinct values 876
(100%)
0
(0%)
47 hs_orless
[numeric]
Mean (sd) : 47.5 (16.8)
min < med < max:
0 < 48.7 < 100
IQR (CV) : 21.2 (0.4)
464 distinct values 876
(100%)
0
(0%)
48 urc2013
[numeric]
Mean (sd) : 2.9 (1.5)
min < med < max:
1 < 3 < 6
IQR (CV) : 2 (0.5)
1 : 203 (23.2%)
2 : 163 (18.6%)
3 : 228 (26.0%)
4 : 123 (14.0%)
5 : 101 (11.5%)
6 : 58 ( 6.6%)
876
(100%)
0
(0%)
49 urc2006
[numeric]
Mean (sd) : 3 (1.5)
min < med < max:
1 < 3 < 6
IQR (CV) : 2 (0.5)
1 : 195 (22.3%)
2 : 162 (18.5%)
3 : 221 (25.2%)
4 : 127 (14.5%)
5 : 115 (13.1%)
6 : 56 ( 6.4%)
876
(100%)
0
(0%)
50 aod
[numeric]
Mean (sd) : 43.7 (19.6)
min < med < max:
5 < 40.2 < 143
IQR (CV) : 18 (0.4)
581 distinct values 876
(100%)
0
(0%)

We can see that for many variables there are many low values as the distribution shows two peaks, one near zero and another with a higher value. This is true for the imp variables (measures of development), the nei variables (measures of emission sources) and the road density variables. We can also see that the range of some of the variables is very large, in particular the area and population related variables.

Evaluate correlation among possible predictors

In prediction analyses, it is also useful to evaluate if any of the variables are correlated.

Intuitively we can expect some of our variables to be correlated.

Let’s first take a look at all of our numeric variabels with thecorrplot package: The corrplot package is another option to look at correlation among possible predictors. This is a great option if we have many predictors. First we need to create a correlation matrix using the cor() function of the stats package (which is loaded automatically).

Using ggcorplot package

We can see that the the development variables (imp) variables are correlated with each other as we might expect. We also see that the road density variables seem to be correlated with each other, and the emission variables seem to be correlated with each other. We can take a closer look using the ggcorr() function and the ggpairs() function of the GGally package. To select our variables of interest we can use the select() function with the contains() function of the tidyr package.

First let’s look at the imp/development variables.

Indeed, we can see that imp_a1000 and imp_a500 are perfectly correlated, as well as imp_a10000, imp_a15000.

Now let’s take a look at the road density data:

We can see that many of the road density variables are highly correlated with one another, while others are less so.

Finally let’s look at the emission variables.

We would also expect the population density data might correlate with some of these variables. Let’s take a look.

Interesting, so these variables don’t appear to be highly correlated, therefore we might need variables from each of the categories to predict our monitor PM2.5 pollution values.

We seem to have some pretty extreme population values though, so let’s see what happens when we take the log value.

Indeed this increased the correlation, but variables from each of these categories may still prove to be useful for prediction.

Data Analysis

Now that we have a sense of what our data is like we can get started with data analysis.

The machine learning process

There are two major types of machine learning:

  1. Unsupervised
  2. Supervised

Unsupervised learning is used to learn about the structure of the data without knowing much about the data. We let the data reveal properties about itself. Examples include clustering the data into groups or reducing the dimensionality of the data using methods like principal component analysis (which we will describe in more detail later) to capture patterns of variance within the data.

source

In contrast, in supervised learning we have some knowledge about the data that we want to use to create a model to be able to generalize about other similar data.

There are two distinct goals of supervised machine learning:

  1. Prediction
  2. Classification

source

We will be performing a prediction analysis (which is also referred to as regression), which aims to predict continuous outcome variables given a number of predictors/explanatory variables/features/parameters, as we have already described.

Classification on the other hand aims to discern or predict group identity for a categorical outcome based on a number of predictors/explanatory variables/features/parameters.

The overall process is the same in either case and involves the following steps (which will each be explained in detail):

  1. Data exploration

We have already performed this step to get a sense of the data. It is important to know if we have NA values, to understand the class of variables, and if to determine if there are any redundant variables that might need to removed.

  1. Data splitting

The data needs to be split into two pieces: a training set and a testing set. The training set will be used to optimize the model, while the testing set will be used to evaluate model performance.

  1. Variable assignment and preprocessing

Both the training and testing data needs to be processed so that the data is compatible and optimized to be used with the model. This involves assigning variables to specific roles within the model and preprocessing like scaling variables and removing redundant variables. This process is also called feature engineering.

  1. Model specification, fitting, tuning and performance evaluation using the training data

The model needs to first be fit to the training data. First the method or algorithm in which the model will be fit is specified (regression, random forest etc.). Then in both classification and prediction, the model is fit to the training data and the explanatory variables are used to estimate numeric values (in the case of prediction) or categorical values (in the case of classification) of the outcome variable of interest. If the model fits well than these estimated values will be very similar to the true outcome variable values. If the model does not fit well, than these estimates will be more disimilar from the true outcome variable. In this case, aspects about the model may need to be modified to improve the similarity of the estimates with that of the true outcome values. One way to optimize model performance is a process called tuning in which different model hyper-parameter options are tested to determine the best option for model performance.

  1. Overall model performance evaluation

Model performance is assessed as the similarity between the estimates of the outcome variable produced by the model and the true outcome variable values. This is done typically as an iterative process with the training data along side modification of the model until the performance using the training data is satisfactory. At this point, the final model performance is assessed using the testing data. This then gives an estimate about how well the model will predict or classify the outcome variable of interest with new independent data. Ideally one would also perform an evaluation with independent data to provide a sense of how generalizable the model is to other data sources.

The tidymodels ecosystem

To perform our analysis we will be using the tidymodels suite of packages. You may be familiar with the older packages caret or mlr which are also for machine learning and modeling but are not a part of the tidyverse. Max Kuhn describes tidymodels like this:

“Other packages, such as caret and mlr, help to solve the R model API issue. These packages do a lot of other things too: preprocessing, model tuning, resampling, feature selection, ensembling, and so on. In the tidyverse, we strive to make our packages modular and parsnip is designed only to solve the interface issue. It is not designed to be a drop-in replacement for caret. The tidymodels package collection, which includes parsnip, has other packages for many of these tasks, and they are designed to work together. We are working towards higher-level APIs that can replicate and extend what the current model packages can do.”

There are many packages in the tidymodels ecosystem which assist with the various steps of the machine learning process:

This is a depiction of how these tools help perform the overall machine learning process:

The major benefits of tidymodels

  1. Standardized workflow/format/notation across different types of algorithms

Different notations are required for different algorithms as the algorithms have been developed by many different people. This would require the painstaking process of reformatting the data to be compatible with each algorithm if multiple algorithms were tested.

  1. Can easily modify preprocessing, algorithm choice, and hyper-parameter tuning making optimization easy

Modifying a piece of the overall process is now much easier than before because many of the steps are specified using the tidymodel packages in a convenient manner. Thus the entire process can be rerun after a simple change to preprocessing without much difficulty.

Splitting the Data

The first step after data exploration in machine learning analysis is to split the data into training and testing datasets.

The training dataset will be used to build and tune our model. This is the data that the model “learns” on.

The testing set will be used to evaluate the performance of our model in a more generalizable way. What do we mean by “generalizable”?

Remember that our main goal is to use our model to be able to predict air pollution levels in areas where there are no gravimetric monitors. Therefore, if our model is super good at predicting air pollution with the data that we use to build it, it might not do the best job for the areas where there are few to no monitors. This would cause us to have really good prediction accuracy and we might assume that we were going to do a good job estimating air pollution any time we use our model, but in fact this would likely not be the case. This situation is what we call overfitting .

Overfitting happens when we end up modeling not only the major relationships in our data but also the noise within our data.

source

If we get fairly good prediction with our testing set then we will know that our model can be applied to other data and will perform fairly well. We will discuss this more later.

We will not touch the testing set until we have completed optimizing our model with the training set. This will allow us to have a less biased evaluation of how well our model can do with other data besides the data used in the training set to build the model. Ideally you would also want a completely independent dataset to further test the performance of your model.

Here is a great description of the differences between testing and training datasets.

We will use the rsample package to perform this step.

Theinitial_split() function allows us to specify how we want to split our data. Typically data is split into 3/4 for training and 1/4 for testing.This is the default proportion and does not need to be specified. However you can change the proportion using the prop argument, which we will do that here for illustrative purposes. You can also specify a variable to stratify by with the strata argument. This is useful if you have imbalanced categorical variables and you would like to intentionally make sure that there are similar number of samples of the rarer categories in both the testing and training sets. Otherwise the split is performed randomly.

The strata argument causes the random sampling to be conducted within the stratification variable. The can help ensure that the number of data points in the training data is equivalent to the proportions in the original data set.

In the case with our dataset, perhaps we would like our training set to have similar proportions of monitors from each of the states as in the initial data. This might be useful if we want our model to be generalizable across all of the states.

We can see that indeed there are different proportions of monitors in each state by using the count() function of the dpyr package.

# A tibble: 49 x 2
   state                    n
   <chr>                <int>
 1 Alabama                 24
 2 Arizona                 17
 3 Arkansas                16
 4 California              85
 5 Colorado                15
 6 Connecticut             14
 7 Delaware                 7
 8 District Of Columbia     3
 9 Florida                 29
10 Georgia                 28
11 Idaho                    7
12 Illinois                38
13 Indiana                 36
14 Iowa                    20
15 Kansas                  10
16 Kentucky                22
17 Louisiana               17
18 Maine                    1
19 Maryland                15
20 Massachusetts           16
21 Michigan                30
22 Minnesota               17
23 Mississippi             12
24 Missouri                13
25 Montana                 16
26 Nebraska                 7
27 Nevada                   4
28 New Hampshire            7
29 New Jersey              23
30 New Mexico              10
31 New York                24
32 North Carolina          35
33 North Dakota             4
34 Ohio                    44
35 Oklahoma                10
36 Oregon                  17
37 Pennsylvania            32
38 Rhode Island             5
39 South Carolina          14
40 South Dakota             9
41 Tennessee                3
42 Texas                   27
43 Utah                    14
44 Vermont                  4
45 Virginia                20
46 Washington               8
47 West Virginia           14
48 Wisconsin               21
49 Wyoming                 12

If our dataset were large enough it might be nice then to stratify by state, but our data is unfortunately not large enough. We will show how one would do this though for illustrative purposes. This option is often more important for classification applications of machine learning than it is for prediction.

Since the split is performed randomly, it is a good idea to use the set.seed() base function to ensure that if your rerun your code that your split will be the same next time. We can see the number of monitors in our training, testing, and original data by typing in the name of our split object. The result will look like this: <training data sample number, testing data sample number, original sample number>

<Analysis/Assess/Total>
<584/292/876>

Importantly the initial_split function only determines what rows of our pm data frame should be assigned for training or testing, it does not actually split the data.

To extract the testing and training data we can use the training() and testing() functions also of the rsample package.

# A tibble: 48 x 2
   state                    n
   <chr>                <int>
 1 Alabama                 18
 2 Arizona                 12
 3 Arkansas                14
 4 California              54
 5 Colorado                12
 6 Connecticut              8
 7 Delaware                 6
 8 District Of Columbia     2
 9 Florida                 18
10 Georgia                 17
# … with 38 more rows
# A tibble: 48 x 2
   state                    n
   <chr>                <int>
 1 Alabama                  6
 2 Arizona                  5
 3 Arkansas                 2
 4 California              31
 5 Colorado                 3
 6 Connecticut              6
 7 Delaware                 1
 8 District Of Columbia     1
 9 Florida                 11
10 Georgia                 11
# … with 38 more rows

Variable Role Assignment and Preprocessing

In tidymodels we will create a recipe, which is a standardized format for a sequence of steps for processing the data.

This can be very useful because it makes testing out different preprocessing steps or different algorithms with the same preprocessing very easy and reproducible.

Creating a recipe specifies how a data frame of predictors should be created - it specifies what variables to be used and the preprocessing steps but it does not execute these steps or create the data frame of predictors.

List the ingredients / specify the variables with the recipe() function

The first thing to do to create a recipe is to specify which variables we will be using as our outcome and predictors using the recipe() function. In terms of the metaphor of baking, we can think of this as listing our ingredients. The naming convention for recipe object names is *_rec or rec.

In our case recall that our value variable, which is the average annual gravimetric monitor PM2.5 concentration in ug/m3. Our predictors are all the other variables except the monitor ID, which is an id variable.

The reason not to include this variable is because this variable includes the county number and a number designating which particular monitor the values came from of the monitors there are in that county. Since this number is arbitrary and the county information is also given in the data, and the fact that each monitor only has one value in the value variable, nothing is gained by including this variable and it may instead introduce noise. However, it is useful to keep this data to take a look at what is happening later. We will show you what to do in this case in just a bit.

The simplest recipe with no preprocessing steps, would be to simply list the outcome and predictor variables.

We can do so in two ways:

  1. Using formula notation
  2. Assigning roles to each variable

Let’s look at the first way using formula notation, which looks like this:

outcome(s) ~ predictor(s)

If in the case of multiple predictors or a multivariate situation with two outcomes, use a plus sign

outcome1 + outcome2 ~ predictor1 + predictor2

If we want to include all predictors we can use a period like so:

outcome_variable_name ~ .

Now with our data we will start by making a recipe for our training data. In the simplest case we might use all predictors like this:

Data Recipe

Inputs:

      role #variables
   outcome          1
 predictor         49

However, to deal with the id variable we could use the update_role() function of the recipes package. This option works well with the newer workflows package, however id variables are often dropped from analyses that do not use this newer package as they can make the process difficult with using the parsnip package alone due to the fact that new levels (or possible values) may be introduced with the testing data.

Data Recipe

Inputs:

        role #variables
 id variable          1
     outcome          1
   predictor         48

We could also specify the outcome and predictors in the same way as the id variable. Please see here for examples of other roles for variables. The role can be actually be any value.

The order is important here, as we first make all variables predictors and then override this role for the outcome and id variable. We will use the everything() function of the dplyr package to start with all of the variables in train_pm.

Data Recipe

Inputs:

        role #variables
 id variable          1
     outcome          1
   predictor         48

If we want to take a look at our formula from our recipe we can do use the formula() function of the stats package.

value ~ fips + lat + lon + state + county + city + CMAQ + zcta + 
    zcta_area + zcta_pop + imp_a500 + imp_a1000 + imp_a5000 + 
    imp_a10000 + imp_a15000 + county_area + county_pop + log_dist_to_prisec + 
    log_pri_length_5000 + log_pri_length_10000 + log_pri_length_15000 + 
    log_pri_length_25000 + log_prisec_length_500 + log_prisec_length_1000 + 
    log_prisec_length_5000 + log_prisec_length_10000 + log_prisec_length_15000 + 
    log_prisec_length_25000 + log_nei_2008_pm25_sum_10000 + log_nei_2008_pm25_sum_15000 + 
    log_nei_2008_pm25_sum_25000 + log_nei_2008_pm10_sum_10000 + 
    log_nei_2008_pm10_sum_15000 + log_nei_2008_pm10_sum_25000 + 
    popdens_county + popdens_zcta + nohs + somehs + hs + somecollege + 
    associate + bachelor + grad + pov + hs_orless + urc2013 + 
    urc2006 + aod
<environment: 0x7f89941e6120>

We can also view our recipe in more detail using the base summary() function.

# A tibble: 50 x 4
   variable type    role        source  
   <chr>    <chr>   <chr>       <chr>   
 1 id       nominal id variable original
 2 value    numeric outcome     original
 3 fips     nominal predictor   original
 4 lat      numeric predictor   original
 5 lon      numeric predictor   original
 6 state    nominal predictor   original
 7 county   nominal predictor   original
 8 city     nominal predictor   original
 9 CMAQ     numeric predictor   original
10 zcta     nominal predictor   original
# … with 40 more rows

List the preprocessing steps using the step functions of the recipe package

The other thing the recipes package allows for is specifying preprocessing steps using a variety of step*() functions.

This link and this link show the many options for recipe step functions.

There are step functions for a variety of purposes:

  1. Imputation – which means filling in missing values based on the existing data
  2. Transformation – which means changing all values of a variable in the same way, typically to make it more normal or easier to interpret)
  3. Discretization – which means converting continuous values into discrete or nominal values - binning for example to reduce the number of possible levels) (However this is generally not advisable!)
  4. Encoding / Creating Dummy Variables – which means creating a numeric code for categorical variables More on Dummy Variables and one hot encoding
  5. Data type conversions – which means changing from integer to factor or numeric to date etc.
  6. Interaction term addition to the model – which means that we would be modeling for predictors that would influence the capacity of each other to predict the outcome
  7. Normalization – which means centering and scaling the data to a similar range of values
  8. Dimensionality Reduction/ Signal Extraction – which means mathematically obtaining a new smaller set of variables that capture the variation or signal in the original variables (ex. Principal Component Analysis and Independent Component Analysis)
  9. Filtering – Filtering options for removing variables (ex. remove variables that are highly correlated to others or remove variables with very little variance and therefore likely little predictive capacity)
  10. Row operations – which means performing functions on the values within the rows (ex. rearranging, filtering, imputing)
  11. Checking functions – Sanity checks to look for missing values, to look at the variable classes etc.

All of the step functions look like step_* except for the check functions which look like check_*.

There are several ways to select what variables to apply steps to:
1) tidyselect methods: contains(), matches(), starts_with(), ends_with(), everything(), num_range()
2) based on the type: all_nominal(), all_numeric() , has_type() 3) based on the role: all_predictors(), all_outcomes(), has_role() 4) name - use the actual name of the variable/variables of interest

Let’s try adding some steps to our recipe.

We might consider log transforming our population and area variables (that aren’t densities) - let’s take a look at the range of these variables.

We can see that the range for each of these variables is quite large, we can log transform this data using the step_log() function of the recipes package.

We would also want to potentially one hot encode some of our categorical variables so that they can be used with certain algorithms. We can do this with the step_dummy() function and the one_hot = TRUE argument. one hot encoding means that we don’t just simply encode our categorical variables numerically, as our numeric assignments can be interpreted by algorithms as having a particular rank or order. Instead, binary variables made of 1s and 0s are used to arbitrarily assign a numeric value that has no apparent order.

Our fips variable includes a numeric code for state and county - and therefore is essentially a proxy for county. Since we already have county, we will just use it and keep the fips id as another ID variable.

We can remove the fips variable from the predictors using update_role() to make sure that the role is no longer "predictor". We can make the role anything we want actually, so we will keep it something identifiable.

We might also want to remove variables that appear to be redundant and are highly correlated with others, as we know from our exploratory data analysis that many of our variables are correlated with one another. We can do this using the step_corr() function.

It is also a good idea to remove variables with near-zero variance, which can be done with the step_nzv() function. Variables have low variance if all the values are very similar, the values are very sparse, or if they are highly imbalanced.

Examples where you might have near-zero variance variables include:

  1. Similar Values - If the population density was nearly the same for every zcta that contained a monitor, then knowing the population density near our monitor would contribute little to our model in assisting us to predict monitor air pollution values.
  2. Sparse Data - If all of the monitors were in locations where the populations did not attend graduate school, then these values would mostly be zero, again this would do very little to help us distinguish our air pollution monitors.When many of the values are zero this is also called sparse data.
  3. Imbalanced Data If nearly all of the monitors were located in one particular state, and all the others only had one monitor each, then the real predictive value would simply be in knowing if a monitor is located in that particular state or not. In this case we don’t want to remove our variable, we just want to simplify it.

See this blog post about why removing near-zero variance variables isn’t always a good idea if we think that a variable might be especially informative.

It is important to add the steps to the recipe in an order that makes sense just like with a cooking recipe.

Thus first we are going to create numeric values for our categorical variables, then we will look at correlation and near-zero variance. We don’t want to remove some of our variables, like the CMAQ and aod variables so we can make sure they are kept in the model by excluding them from those steps. If we specifically wanted to remove a predictor we could use step_rm().

Data Recipe

Inputs:

        role #variables
   county id          1
 id variable          1
     outcome          1
   predictor         47

Operations:

Dummy variables from state, county, city, zcta
Correlation filter on all_predictors, -, CMAQ, -, aod
Sparse, unbalanced variable filter on all_predictors, -, CMAQ, -, aod

Running the preprocessing

The next major function of the recipes package is prep().

This function updates the recipe object based on the training data. It estimates parameters (estimating the required quantities and statistics required by the steps for the variables) for preprocessing and updates the model terms, as some of the predictors may be removed, this allows the recipe to be ready to use on other datasets. It doesn’t necessarily actually execute the preprocessing itself, however we will specify in argument for it to do this so that we can take a look at the preprocessed data.

There are some important arguments to know about: 1) training - you must supply a training data set to estimate parameters for preprocessing operations (recipe steps) - this may already be included in your recipe - as is the case for us 2) fresh - if TRUE - will retrain and estimate parameters for any previous steps that were already prepped if you add more steps to the recipe 3) verbose - if TRUE shows the progress as the steps are evaluated and the size of the preprocessed training set 4) retain - if TRUE then the preprocessed training set will be saved within the recipe (as template). This is good if you are likely to add more steps and don’t want to rerun the prep() on the previous steps. However this can make the recipe size large. This is necessary if you want to actually look at the preprocessed data.

oper 1 step dummy [training] 
oper 2 step corr [training] 
oper 3 step nzv [training] 
The retained training set is ~ 0.26 Mb  in memory.
[1] "var_info"       "term_info"      "steps"          "template"      
[5] "levels"         "retained"       "tr_info"        "orig_lvls"     
[9] "last_term_info"

There are also lots of useful things to checkout in the output of prep(). You can see: 1) the steps that were run
2) the variable info (var_info)
3) the model term_info 4) the new levels of the variables 5) the original levels of the variables orig_lvls
6) info about the training data set size and completeness (tr_info)

Note: You may see the prep.recipe() function in material that you read about the recipes package. This is referring to the prep() function of the recipes package.

Extracting the preprocessed training data

Since we retained our preprocessed training data, we can take a look at it like by using the juice() function of the recipes package like this:

Rows: 584
Columns: 36
$ id                          <fct> 1003.001, 1027.0001, 1033.1002, 1055.001,…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 12.375394…
$ fips                        <fct> 1003, 1027, 1033, 1055, 1069, 1073, 1073,…
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 33.99375, 3…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85.9910…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 9.241744, 9…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 154069359…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 20045, 30217, 9010, 16…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038, 16.4…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 5.161210…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, 13856…
$ county_pop                  <dbl> 182265, 13932, 54428, 104430, 101547, 658…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 5.261457, 7…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 9.066563, 8…
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 12.01356, 1…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 8.740680, 6…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 9.627898, 7…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 11.72888…
$ log_prisec_length_10000     <dbl> 11.886803, 11.405543, 12.840663, 12.76827…
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, 4.462…
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 4.678311, 3…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 75.367038…
$ popdens_zcta                <dbl> 145.7164307, 13.6395554, 540.8870404, 130…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 4.3, 5.8, 7.1, 2.7, 11.1,…
$ somehs                      <dbl> 4.9, 19.1, 15.8, 13.3, 11.6, 17.1, 6.6, 1…
$ hs                          <dbl> 25.1, 33.9, 30.6, 27.8, 29.8, 37.2, 30.7,…
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 29.2, 21.4, 23.5, 25.7,…
$ associate                   <dbl> 8.2, 8.0, 7.6, 10.1, 7.9, 7.3, 8.0, 4.1, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 10.0, 13.7, 5.9, 17.6, 7…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.4, 9.8, 2.0, 8.7, 2.9, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 8.8, 15.6, 25.5, 7.3, 8.…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 45.4, 47.2, 61.4, 40.0,…
$ urc2013                     <dbl> 4, 6, 4, 4, 4, 1, 1, 1, 1, 1, 2, 3, 3, 3,…
$ aod                         <dbl> 37.363636, 34.818182, 36.000000, 43.41666…
$ state_California            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ city_Not.in.a.city          <dbl> 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0,…

For easy comparison sake - here is our original data:

Rows: 876
Columns: 50
$ id                          <fct> 1003.001, 1027.0001, 1033.1002, 1049.1003…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 11.659091…
$ fips                        <fct> 1003, 1027, 1033, 1049, 1055, 1069, 1073,…
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 34.28763, 3…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85.9683…
$ state                       <chr> "Alabama", "Alabama", "Alabama", "Alabama…
$ county                      <chr> "Baldwin", "Clay", "Colbert", "DeKalb", "…
$ city                        <chr> "Fairhope", "Ashland", "Muscle Shoals", "…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 8.534772, 9…
$ zcta                        <fct> 36532, 36251, 35660, 35962, 35901, 36303,…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 203836235…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 8300, 20045, 30217, 90…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038, 5.78…
$ imp_a1000                   <dbl> 1.4096021, 0.8531574, 11.1448962, 3.86764…
$ imp_a5000                   <dbl> 3.3360118, 0.9851479, 15.1786154, 1.23114…
$ imp_a10000                  <dbl> 1.9879187, 0.5208189, 9.7253870, 1.031646…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 0.973044…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, 20126…
$ county_pop                  <dbl> 182265, 13932, 54428, 71109, 104430, 1015…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 3.721489, 5…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 8.517193, 9…
$ log_pri_length_10000        <dbl> 9.210340, 9.210340, 9.274303, 10.409411, …
$ log_pri_length_15000        <dbl> 9.630228, 9.615805, 9.658899, 11.173626, …
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 11.90959, 1…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 7.310155, 8…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 8.585843, 9…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 10.21420…
$ log_prisec_length_10000     <dbl> 11.88680, 11.40554, 12.84066, 11.50894, 1…
$ log_prisec_length_15000     <dbl> 12.205723, 12.042963, 13.282656, 12.35366…
$ log_prisec_length_25000     <dbl> 13.41395, 12.79980, 13.79973, 13.55979, 1…
$ log_nei_2008_pm25_sum_10000 <dbl> 0.318035438, 3.218632928, 6.573127301, 0.…
$ log_nei_2008_pm25_sum_15000 <dbl> 1.967358961, 3.218632928, 6.581917457, 3.…
$ log_nei_2008_pm25_sum_25000 <dbl> 5.067308, 3.218633, 6.875900, 4.887665, 4…
$ log_nei_2008_pm10_sum_10000 <dbl> 1.35588511, 3.31111648, 6.69187313, 0.000…
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, 3.350…
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 5.171920, 4…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 35.330814…
$ popdens_zcta                <dbl> 145.716431, 13.639555, 540.887040, 40.718…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 14.3, 4.3, 5.8, 7.1, 2.7,…
$ somehs                      <dbl> 4.9, 19.1, 15.8, 16.7, 13.3, 11.6, 17.1, …
$ hs                          <dbl> 25.1, 33.9, 30.6, 35.0, 27.8, 29.8, 37.2,…
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 14.9, 29.2, 21.4, 23.5,…
$ associate                   <dbl> 8.2, 8.0, 7.6, 5.5, 10.1, 7.9, 7.3, 8.0, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 7.9, 10.0, 13.7, 5.9, 17…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.8, 5.4, 9.8, 2.0, 8.7, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 13.8, 8.8, 15.6, 25.5, 7…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 66.0, 45.4, 47.2, 61.4,…
$ urc2013                     <dbl> 4, 6, 4, 6, 4, 4, 1, 1, 1, 1, 1, 1, 1, 2,…
$ urc2006                     <dbl> 5, 6, 4, 5, 4, 4, 1, 1, 1, 1, 1, 1, 1, 2,…
$ aod                         <dbl> 37.36364, 34.81818, 36.00000, 33.08333, 4…

Notice how we only have 36 variables now instead of 50! Two of these are our ID variables (fips and the actual monitor ID (id)) and one is our outcome (value). Thus we only have 33 predictors now. We can also see that variables that we no longer have any categorical variables. Variables like state are gone and only state_California remains as it was the only state identity to have nonzero variance. We can see that California had the largest number of monitors compared to the other states. We can also see that there were more monitors listed as "Not in a city" than any city.

# A tibble: 49 x 2
   state                    n
   <chr>                <int>
 1 Alabama                 24
 2 Arizona                 17
 3 Arkansas                16
 4 California              85
 5 Colorado                15
 6 Connecticut             14
 7 Delaware                 7
 8 District Of Columbia     3
 9 Florida                 29
10 Georgia                 28
11 Idaho                    7
12 Illinois                38
13 Indiana                 36
14 Iowa                    20
15 Kansas                  10
16 Kentucky                22
17 Louisiana               17
18 Maine                    1
19 Maryland                15
20 Massachusetts           16
21 Michigan                30
22 Minnesota               17
23 Mississippi             12
24 Missouri                13
25 Montana                 16
26 Nebraska                 7
27 Nevada                   4
28 New Hampshire            7
29 New Jersey              23
30 New Mexico              10
31 New York                24
32 North Carolina          35
33 North Dakota             4
34 Ohio                    44
35 Oklahoma                10
36 Oregon                  17
37 Pennsylvania            32
38 Rhode Island             5
39 South Carolina          14
40 South Dakota             9
41 Tennessee                3
42 Texas                   27
43 Utah                    14
44 Vermont                  4
45 Virginia                20
46 Washington               8
47 West Virginia           14
48 Wisconsin               21
49 Wyoming                 12

# A tibble: 607 x 2
    city                                                 n
    <chr>                                            <int>
  1 Aberdeen                                             1
  2 Akron                                                2
  3 Albany                                               3
  4 Albuquerque                                          2
  5 Alexandria                                           1
  6 Allen Park                                           1
  7 Altamont                                             1
  8 Alton                                                1
  9 Amarillo                                             1
 10 Anadarko                                             1
 11 Anaheim                                              1
 12 Anderson                                             1
 13 Annandale                                            1
 14 Apache Junction                                      1
 15 Apple Valley                                         1
 16 Appleton                                             1
 17 Arden-Arcade                                         1
 18 Arlington                                            1
 19 Arnold                                               1
 20 Asheville                                            1
 21 Ashland                                              2
 22 Atascadero                                           1
 23 Athens-Clarke County (Remainder)                     1
 24 Atlanta                                              2
 25 Atlantic City                                        1
 26 Augusta-Richmond County (Remainder)                  2
 27 Aurora                                               1
 28 Austin                                               1
 29 Azusa                                                1
 30 Bakersfield                                          3
 31 Baltimore                                            5
 32 Batavia                                              1
 33 Baton Rouge                                          1
 34 Bay City                                             1
 35 Bayport                                              1
 36 Baytown                                              1
 37 Beaver Falls                                         1
 38 Beckley                                              1
 39 Belle Glade                                          1
 40 Bellevue                                             1
 41 Beltsville                                           1
 42 Bend                                                 1
 43 Bennington                                           1
 44 Bensley                                              1
 45 Big Bear City                                        1
 46 Billings                                             1
 47 Birmingham                                           2
 48 Bismarck                                             1
 49 Bladensburg                                          1
 50 Blair                                                1
 51 Blue Ash                                             1
 52 Blue Island                                          1
 53 Boise (corporate name Boise City)                    1
 54 Boone                                                1
 55 Boston                                               4
 56 Boulder                                              1
 57 Boulevard                                            1
 58 Bountiful                                            1
 59 Braidwood                                            1
 60 Brawley                                              1
 61 Bridgeport                                           1
 62 Brigham City                                         1
 63 Bristol                                              2
 64 Brockton                                             1
 65 Brook Park                                           1
 66 Brookings                                            1
 67 Brunswick                                            1
 68 Bryson City (RR name Bryson)                         1
 69 Buffalo                                              1
 70 Burbank                                              1
 71 Burlington                                           2
 72 Burns                                                1
 73 Butte-Silver Bow (Remainder)                         1
 74 Calexico                                             1
 75 Camden                                               1
 76 Candor                                               1
 77 Canton                                               2
 78 Carlisle                                             1
 79 Carlstadt                                            3
 80 Cary                                                 1
 81 Casa Grande                                          1
 82 Cedar Rapids                                         2
 83 Cedarhurst                                           1
 84 Central Point                                        1
 85 Chalmette                                            1
 86 Champaign                                            1
 87 Chapel Hill                                          1
 88 Charleroi                                            1
 89 Charleston                                           2
 90 Charlotte                                            2
 91 Chattanooga                                          1
 92 Chelmsford (Chelmsford Center)                       1
 93 Chester                                              2
 94 Cheyenne                                             1
 95 Chicago                                              5
 96 Chickasaw                                            1
 97 Chicopee                                             1
 98 Childersburg                                         1
 99 Chula Vista                                          1
100 Cicero                                               1
101 Cincinnati                                           3
102 Clairton                                             1
103 Claremont                                            1
104 Clarion                                              1
105 Clarksburg                                           1
106 Clearwater                                           1
107 Cleveland                                            6
108 Clinton                                              2
109 Clive                                                1
110 Clovis                                               1
111 Cockeysville                                         1
112 Cody                                                 1
113 Coloma                                               1
114 Colorado Springs                                     1
115 Columbia                                             1
116 Columbia Falls                                       1
117 Columbus                                             4
118 Columbus (Remainder)                                 3
119 Colusa                                               1
120 Commerce City                                        1
121 Concord                                              1
122 Conway                                               1
123 Corcoran                                             1
124 Cornwall                                             1
125 Corpus Christi                                       2
126 Cottage Grove                                        1
127 Cottonwood West                                      1
128 Council Bluffs                                       1
129 Covington                                            1
130 Crossett                                             1
131 Crossville                                           1
132 Dale                                                 1
133 Dallas                                               3
134 Danbury                                              1
135 Darrington                                           1
136 Davenport                                            3
137 Davie                                                1
138 Dayton                                               1
139 Dearborn                                             1
140 Decatur                                              2
141 Delray Beach                                         1
142 Dentsville (Dents)                                   1
143 Denver                                               3
144 Des Moines                                           1
145 Des Plaines                                          1
146 Detroit                                              5
147 Doraville                                            1
148 Dothan                                               1
149 Douglas                                              1
150 Dover                                                1
151 Duluth                                               2
152 Durham                                               1
153 East Chicago                                         1
154 East Farmingdale                                     1
155 East Hartford                                        2
156 East Highland Park                                   1
157 East Providence                                      1
158 East Ridge                                           1
159 East Saint Louis                                     1
160 East Syracuse                                        1
161 Edgewood                                             1
162 El Cajon                                             1
163 El Centro                                            1
164 El Dorado                                            1
165 El Paso                                              3
166 Elgin                                                1
167 Elizabeth                                            2
168 Elizabethtown                                        1
169 Elkhart                                              1
170 Emmetsburg                                           1
171 Erie                                                 1
172 Escondido                                            1
173 Essex                                                1
174 Eugene                                               2
175 Eureka                                               2
176 Evansville                                           3
177 Fairfield                                            1
178 Fairhope                                             1
179 Fairmont                                             1
180 Fall River                                           1
181 Farmington                                           1
182 Farrell                                              1
183 Fayetteville                                         1
184 Ferry Pass                                           1
185 Flagstaff                                            1
186 Flint                                                1
187 Follansbee                                           1
188 Fontana                                              1
189 Forest Park                                          1
190 Fort Collins                                         1
191 Fort Defiance                                        1
192 Fort Lee                                             1
193 Fort Myers                                           1
194 Fort Pierce                                          1
195 Fort Smith                                           1
196 Fort Wayne                                           1
197 Fort Worth                                           2
198 Frankfort                                            1
199 Franklin                                             1
200 Freemansburg                                         1
201 Fremont                                              1
202 Fresno                                               2
203 Gadsden                                              1
204 Gainesville                                          3
205 Galloway (Township of)                               1
206 Garden City                                          1
207 Gary                                                 3
208 Gastonia                                             1
209 Gilroy                                               1
210 Glen Burnie                                          1
211 Goldsboro                                            1
212 Gordon                                               1
213 Grand Island                                         1
214 Grand Junction                                       1
215 Grand Rapids                                         2
216 Granite City                                         2
217 Grants Pass                                          1
218 Grass Valley                                         1
219 Great Falls                                          1
220 Greater Upper Marlboro                               1
221 Greeley                                              1
222 Green Bay                                            1
223 Greensboro                                           1
224 Greensburg                                           1
225 Greenville                                           3
226 Greenwich (Township of)                              1
227 Grenada                                              1
228 Griffith                                             1
229 Groveton                                             1
230 Gulfport                                             1
231 Hamilton                                             1
232 Hammond                                              3
233 Hampton                                              1
234 Harrison Township                                    1
235 Harrisville                                          1
236 Hattiesburg                                          1
237 Haverhill                                            1
238 Helena                                               2
239 Helena Valley West Central                           1
240 Hernando                                             1
241 Hickory                                              1
242 Highland                                             1
243 Highland Heights                                     1
244 Hillsboro                                            1
245 Hobbs                                                1
246 Holland                                              1
247 Hollister                                            1
248 Hollywood                                            1
249 Homestead                                            1
250 Hoover                                               1
251 Hopewell (Township of)                               1
252 Hot Springs (Hot Springs National Park)              1
253 Houston                                              2
254 Huntington                                           1
255 Huntsville                                           1
256 Indianapolis                                         1
257 Indianapolis (Remainder)                             4
258 Indio                                                1
259 Iowa City                                            1
260 Ironton                                              1
261 Jackson                                              2
262 Jacksonville                                         2
263 Jamesville                                           1
264 Jasper                                               3
265 Jean                                                 1
266 Jeffersonville                                       1
267 Jenison                                              1
268 Jersey City                                          1
269 Jerseyville                                          1
270 Johnstown                                            1
271 Joliet                                               1
272 Kalamazoo                                            1
273 Kalispell                                            1
274 Kansas City                                          3
275 Keeler                                               1
276 Keene                                                1
277 Kenansville                                          1
278 Kenner                                               1
279 Kennesaw                                             1
280 Keokuk                                               1
281 Kinston                                              1
282 Kokomo                                               1
283 La Crosse                                            1
284 La Grande                                            1
285 Lackawanna                                           1
286 Laconia                                              1
287 Ladue                                                1
288 Lafayette                                            3
289 Lake Charles                                         1
290 Lakeland                                             1
291 Lakeport                                             1
292 Lakeview                                             1
293 Lancaster                                            2
294 Lander                                               1
295 Lansing                                              1
296 Las Cruces                                           1
297 Las Vegas                                            1
298 Laurel                                               1
299 Lawrence                                             1
300 Leander                                              1
301 Lebanon                                              2
302 Leeds                                                1
303 Lexington                                            1
304 Lexington-Fayette (corporate name for Lexington)     2
305 Libby                                                1
306 Liberty                                              1
307 Lincoln                                              1
308 Lindon                                               1
309 Little Rock                                          2
310 Littleton                                            1
311 Live Oak                                             1
312 Livermore                                            1
313 Livonia                                              1
314 Logan                                                1
315 Long Beach                                           2
316 Longmont                                             1
317 Los Angeles                                          1
318 Louisville                                           4
319 Luna Pier                                            1
320 Lynchburg                                            1
321 Lynn                                                 1
322 Lynwood                                              1
323 Macon                                                2
324 Madison                                              1
325 Magna                                                1
326 Mamaroneck                                           1
327 Manistee                                             1
328 Marble City Community                                1
329 Maricopa                                             1
330 Marion                                               2
331 Marrero                                              1
332 Martinsburg                                          1
333 Marysville                                           1
334 McAlester                                            1
335 McCook                                               1
336 McDonald                                             1
337 McLean                                               1
338 Medford                                              1
339 Melbourne                                            1
340 Mena                                                 1
341 Merced                                               1
342 Meridian                                             1
343 Mesa                                                 1
344 Miami                                                2
345 Michigan City                                        1
346 Middlesborough (corporate name for Middlesboro)      1
347 Middletown                                           2
348 Midlothian                                           1
349 Milwaukee                                            5
350 Mingo Junction                                       1
351 Minneapolis                                          2
352 Mira Loma                                            1
353 Mission                                              1
354 Mission Viejo                                        1
355 Missoula                                             1
356 Modesto                                              1
357 Mojave                                               1
358 Monroe                                               1
359 Montgomery                                           1
360 Morgantown                                           1
361 Morristown                                           1
362 Moundsville                                          1
363 Muncie                                               1
364 Muscatine                                            1
365 Muscle Shoals                                        1
366 Muskegon                                             1
367 Muskogee                                             1
368 Naperville                                           1
369 Nashua                                               1
370 Natchez                                              1
371 New Albany                                           1
372 New Haven                                            5
373 New Paris                                            1
374 New York                                             9
375 Newark                                               2
376 Newburgh                                             1
377 Newburgh Heights                                     1
378 Newport                                              1
379 Niagara Falls                                        1
380 Nogales                                              1
381 Norfolk                                              1
382 Normal                                               1
383 Norristown                                           1
384 North Braddock                                       1
385 North Brunswick Township                             1
386 North Charleston                                     1
387 North Las Vegas                                      1
388 North Little Rock                                    1
389 Northbrook                                           1
390 Norwalk                                              1
391 Norwich                                              1
392 Norwood                                              1
393 Not in a city                                      103
394 Oak Park                                             1
395 Oakland                                              2
396 Oakridge                                             1
397 Odessa                                               1
398 Ogden                                                1
399 Ogden Dunes (Wickliffe)                              1
400 Oglesby                                              1
401 Oklahoma City                                        2
402 Omaha                                                2
403 Onamia                                               1
404 Ontario                                              1
405 Orlando                                              1
406 Overland Park                                        1
407 Paducah                                              1
408 Painesville                                          1
409 Palm Springs                                         1
410 Palm Springs North                                   1
411 Panama City                                          1
412 Pasadena                                             1
413 Pascagoula                                           1
414 Paterson                                             1
415 Pawtucket                                            1
416 Peach Springs                                        1
417 Pelham                                               1
418 Pendleton                                            1
419 Pennsauken (Pensauken)                               1
420 Peoria                                               1
421 Phenix City                                          1
422 Philadelphia                                         5
423 Phillipsburg                                         1
424 Phoenix                                              3
425 Pico Rivera                                          1
426 Pikeville                                            1
427 Pinedale                                             1
428 Pinehurst (Pine Creek)                               1
429 Pinson                                               1
430 Piru                                                 1
431 Pittsboro                                            1
432 Pittsburgh                                           1
433 Pittsfield                                           1
434 Platteville                                          1
435 Pleasant Prairie                                     1
436 Pompano Beach                                        1
437 Port Arthur                                          1
438 Port Huron                                           1
439 Portland                                             2
440 Portola                                              1
441 Portsmouth                                           2
442 Potosi                                               1
443 Potsdam                                              1
444 Powder Springs                                       1
445 Prescott Valley                                      1
446 Presque Isle                                         1
447 Providence                                           2
448 Provo                                                1
449 Pryor (corporate name Pryor Creek)                   1
450 Pueblo                                               1
451 Quincy                                               2
452 Rahway                                               1
453 Raleigh                                              1
454 Rapid City                                           2
455 Ravenna                                              1
456 Redding                                              1
457 Redwood City                                         1
458 Reno                                                 1
459 Reseda                                               1
460 Richfield                                            1
461 Richmond                                             1
462 Ridge Wood Heights                                   1
463 Ridgecrest                                           1
464 Rio Rancho Estates                                   1
465 Riverside                                            1
466 Roanoke                                              2
467 Rochester                                            2
468 Rock Island Arsenal (U.S. Army)                      1
469 Rock Springs                                         1
470 Rockford                                             1
471 Rockwell                                             1
472 Rocky Mount                                          1
473 Rome                                                 1
474 Roseville                                            1
475 Roswell                                              1
476 Roxborough Park                                      1
477 Royal Palm Beach                                     1
478 Rubidoux                                             1
479 Russellville                                         1
480 Rutland                                              1
481 Sacramento                                           2
482 Saint Petersburg                                     1
483 Salinas                                              1
484 Salt Lake City                                       2
485 San Andreas                                          1
486 San Antonio                                          2
487 San Bernardino                                       1
488 San Diego                                            2
489 San Francisco                                        1
490 San Jose                                             1
491 San Luis Obispo                                      1
492 Sandersville                                         1
493 Sanford                                              1
494 Santa Barbara                                        1
495 Santa Fe                                             1
496 Santa Maria                                          1
497 Santa Rosa                                           1
498 Sault Ste. Marie                                     2
499 Savannah                                             1
500 Schiller Park                                        1
501 Scottsbluff                                          1
502 Scottsdale                                           1
503 Scranton                                             1
504 Seaford                                              1
505 Searcy                                               1
506 Seattle                                              2
507 Seeley Lake                                          1
508 Seven Oaks                                           1
509 Shakopee                                             1
510 Sharonville                                          1
511 Shasta Lake                                          1
512 Sheffield                                            1
513 Shepherdsville                                       1
514 Sheridan                                             2
515 Shreveport                                           1
516 Silver City                                          1
517 Simi Valley                                          1
518 Sioux City                                           1
519 Sioux Falls                                          2
520 Soddy-Daisy                                          1
521 South Bend                                           2
522 South Charleston                                     1
523 South Padre Island                                   1
524 Spanish Fork                                         1
525 Spokane                                              1
526 Springdale                                           1
527 Springfield                                          5
528 Spruce Pine                                          1
529 St. Bernard                                          1
530 St. Cloud                                            1
531 St. Joseph                                           1
532 St. Louis                                            4
533 St. Louis Park                                       1
534 St. Paul                                             3
535 State College                                        1
536 Ste. Genevieve                                       1
537 Steubenville                                         1
538 Stockton                                             1
539 Stuttgart                                            1
540 Summit                                               1
541 Suncook                                              1
542 Swansea                                              1
543 Tacoma                                               1
544 Tallahassee                                          1
545 Tampa                                                1
546 Taylors                                              1
547 Tecumseh                                             1
548 Terre Haute                                          2
549 Texarkana                                            1
550 Theodore                                             1
551 Thomaston                                            1
552 Thompson Falls                                       1
553 Thousand Oaks                                        1
554 Toledo                                               3
555 Toms River                                           1
556 Tooele                                               1
557 Topeka                                               1
558 Trenton                                              1
559 Truckee                                              1
560 Tucson                                               2
561 Tulsa                                                2
562 Tupelo                                               1
563 Tuscaloosa                                           1
564 Ukiah                                                1
565 Underhill (Town of)                                  1
566 Union City                                           1
567 Valdosta                                             1
568 Vallejo                                              1
569 Valrico                                              1
570 Vancouver                                            1
571 Victorville                                          1
572 Vienna                                               1
573 Vinton                                               1
574 Virginia                                             1
575 Virginia Beach                                       1
576 Visalia                                              1
577 Warner Robins                                        1
578 Warren                                               1
579 Washington                                           4
580 Waterbury                                            1
581 Waterloo                                             1
582 Watertown                                            1
583 Waukesha                                             1
584 Waynesville                                          1
585 Weirton                                              2
586 West Orange                                          1
587 West Yellowstone                                     1
588 Westfield                                            1
589 Westport                                             1
590 Wheeling                                             1
591 Whitefish                                            1
592 Wichita                                              3
593 Wilmington                                           1
594 Winston-Salem                                        2
595 Winter Park                                          1
596 Wood River                                           1
597 Woodland                                             1
598 Worcester                                            2
599 Wyandotte                                            1
600 Yakima                                               1
601 Yellow Springs                                       1
602 York                                                 1
603 Youngstown                                           2
604 Ypsilanti                                            1
605 Yuba City                                            1
606 Yuma                                                 1
607 Zion                                                 1

Note: Recall that you must specify retain = TRUE argument of the prep() function to use juice().

Extracting the preprocessed testing data

According to the tidymodels documentation:

bake() takes a trained recipe and applies the operations to a data set to create a design matrix. for example: it applies the centering to new data sets using these means used to create the recipe

If you wanted to look at the preprocessed testing data you would use the bake() function of the recipes package. (You generally want to leave your testing data alone, but it is good to look for issues like the introduction of NA values).

Rows: 292
Columns: 36
$ id                          <fct> 1049.1003, 1073.101, 1073.2006, 1089.0014…
$ value                       <dbl> 11.659091, 13.114545, 12.228125, 12.23294…
$ fips                        <fct> 1049, 1073, 1073, 1089, 1103, 1121, 4013,…
$ lat                         <dbl> 34.28763, 33.54528, 33.38639, 34.68767, 3…
$ lon                         <dbl> -85.96830, -86.54917, -86.81667, -86.5863…
$ CMAQ                        <dbl> 8.534772, 9.303766, 10.235612, 9.343611, …
$ zcta_area                   <dbl> 203836235, 148994881, 56063756, 46963946,…
$ zcta_pop                    <dbl> 8300, 14212, 32390, 21297, 30545, 7713, 5…
$ imp_a500                    <dbl> 5.78200692, 0.06055363, 42.42820069, 23.2…
$ imp_a15000                  <dbl> 0.9730444, 2.9956557, 12.7487614, 10.3555…
$ county_area                 <dbl> 2012662359, 2878192209, 2878192209, 20761…
$ county_pop                  <dbl> 71109, 658466, 658466, 334811, 119490, 82…
$ log_dist_to_prisec          <dbl> 3.721489, 7.301545, 4.721755, 4.659519, 6…
$ log_pri_length_5000         <dbl> 8.517193, 9.683336, 10.737240, 8.517193, …
$ log_pri_length_25000        <dbl> 11.90959, 12.53777, 12.99669, 11.47391, 1…
$ log_prisec_length_500       <dbl> 7.310155, 6.214608, 7.528913, 8.760549, 6…
$ log_prisec_length_1000      <dbl> 8.585843, 7.600902, 9.342290, 9.543183, 8…
$ log_prisec_length_5000      <dbl> 10.214200, 11.262645, 11.713190, 11.48606…
$ log_prisec_length_10000     <dbl> 11.50894, 12.14101, 12.53899, 12.68440, 1…
$ log_nei_2008_pm10_sum_15000 <dbl> 3.3500444, 6.6241114, 5.8268686, 3.861625…
$ log_nei_2008_pm10_sum_25000 <dbl> 5.1719202, 7.5490587, 8.8205542, 5.219092…
$ popdens_county              <dbl> 35.330814, 228.777633, 228.777633, 161.26…
$ popdens_zcta                <dbl> 40.718962, 95.385827, 577.735106, 453.475…
$ nohs                        <dbl> 14.3, 7.2, 0.8, 1.2, 4.8, 16.7, 19.1, 6.4…
$ somehs                      <dbl> 16.7, 12.2, 2.6, 3.1, 7.8, 33.3, 15.6, 9.…
$ hs                          <dbl> 35.0, 32.2, 12.9, 15.1, 28.7, 37.5, 26.5,…
$ somecollege                 <dbl> 14.9, 19.0, 17.9, 20.5, 25.0, 12.5, 18.0,…
$ associate                   <dbl> 5.5, 6.8, 5.2, 6.5, 7.5, 0.0, 6.0, 8.8, 3…
$ bachelor                    <dbl> 7.9, 14.8, 35.5, 30.4, 18.2, 0.0, 10.6, 1…
$ grad                        <dbl> 5.8, 7.7, 25.2, 23.3, 8.0, 0.0, 4.1, 5.7,…
$ pov                         <dbl> 13.8, 10.5, 2.1, 5.2, 8.3, 18.8, 21.4, 14…
$ hs_orless                   <dbl> 66.0, 51.6, 16.3, 19.4, 41.3, 87.5, 61.2,…
$ urc2013                     <dbl> 6, 1, 1, 3, 4, 5, 1, 2, 5, 4, 4, 6, 6, 1,…
$ aod                         <dbl> 33.08333, 42.45455, 44.25000, 42.41667, 4…
$ state_California            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,…
$ city_Not.in.a.city          <dbl> NA, NA, NA, NA, NA, NA, 0, NA, NA, NA, NA…

Notice that our city_Not.in.a.city variable seems to be NA values. Why might that be?

Ah! Perhaps it is because some of our levels were not previously seen in the training set!

Let’s take a look using the set operations of the dplyr package. We can take a look at cities that were different between the test and training set.

[1] 376   1
[1] 51  1

Indeed, there are lots of different cities in our test data that are not in our training data!

Maybe remove this?: Thus we need to update our original recipe to include a very important step function called step_novel() this helps in cases like this were there are new factors in our testing set that were not in our training set. It is a good idea to include this in most of your recipes where you have a categorical variables with many distinct values. This step needs to come before we create dummy variables. However, we are also creating a dummy variable from this, which still results in a problem.

Let’s modify the city variable to be values of in a city or not in a city using the if_else() function of dplyr. Alternatively you could create a custom step function to do this and add the step function to your recipe, but that is beyond the scope of this case study.

We need to create a new recipe to move forward, as the levels of our variables are established then. We would also potentially have this issue for state and county. So let’s also do a similar thing for state. The county variables appears to get dropped due to either correlation or near zero variance. It is likely due to near zero variance because this is the more granular of these geographic categorical variables and likely sparse.

<Analysis/Assess/Total>
<584/292/876>

Now let’s retrain our training data and try baking our test data:

oper 1 step dummy [training] 
oper 2 step corr [training] 
oper 3 step nzv [training] 
The retained training set is ~ 0.26 Mb  in memory.

Rows: 584
Columns: 37
$ id                          <fct> 1003.001, 1027.0001, 1033.1002, 1055.001,…
$ value                       <dbl> 9.597647, 10.800000, 11.212174, 12.375394…
$ fips                        <fct> 1003, 1027, 1033, 1055, 1069, 1073, 1073,…
$ lat                         <dbl> 30.49800, 33.28126, 34.75878, 33.99375, 3…
$ lon                         <dbl> -87.88141, -85.80218, -87.65056, -85.9910…
$ CMAQ                        <dbl> 8.098836, 9.766208, 9.402679, 9.241744, 9…
$ zcta_area                   <dbl> 190980522, 374132430, 16716984, 154069359…
$ zcta_pop                    <dbl> 27829, 5103, 9042, 20045, 30217, 9010, 16…
$ imp_a500                    <dbl> 0.01730104, 1.96972318, 19.17301038, 16.4…
$ imp_a15000                  <dbl> 1.4386207, 0.3359198, 5.2472094, 5.161210…
$ county_area                 <dbl> 4117521611, 1564252280, 1534877333, 13856…
$ county_pop                  <dbl> 182265, 13932, 54428, 104430, 101547, 658…
$ log_dist_to_prisec          <dbl> 4.648181, 7.219907, 5.760131, 5.261457, 7…
$ log_pri_length_5000         <dbl> 8.517193, 8.517193, 8.517193, 9.066563, 8…
$ log_pri_length_25000        <dbl> 11.32735, 10.12663, 10.15769, 12.01356, 1…
$ log_prisec_length_500       <dbl> 7.295356, 6.214608, 8.611945, 8.740680, 6…
$ log_prisec_length_1000      <dbl> 8.195119, 7.600902, 9.735569, 9.627898, 7…
$ log_prisec_length_5000      <dbl> 10.815042, 10.170878, 11.770407, 11.72888…
$ log_prisec_length_10000     <dbl> 11.886803, 11.405543, 12.840663, 12.76827…
$ log_prisec_length_25000     <dbl> 13.41395, 12.79980, 13.79973, 13.70026, 1…
$ log_nei_2008_pm10_sum_15000 <dbl> 2.26783411, 3.31111648, 6.70127741, 4.462…
$ log_nei_2008_pm10_sum_25000 <dbl> 5.628728, 3.311116, 7.148858, 4.678311, 3…
$ popdens_county              <dbl> 44.265706, 8.906492, 35.460814, 75.367038…
$ popdens_zcta                <dbl> 145.7164307, 13.6395554, 540.8870404, 130…
$ nohs                        <dbl> 3.3, 11.6, 7.3, 4.3, 5.8, 7.1, 2.7, 11.1,…
$ somehs                      <dbl> 4.9, 19.1, 15.8, 13.3, 11.6, 17.1, 6.6, 1…
$ hs                          <dbl> 25.1, 33.9, 30.6, 27.8, 29.8, 37.2, 30.7,…
$ somecollege                 <dbl> 19.7, 18.8, 20.9, 29.2, 21.4, 23.5, 25.7,…
$ associate                   <dbl> 8.2, 8.0, 7.6, 10.1, 7.9, 7.3, 8.0, 4.1, …
$ bachelor                    <dbl> 25.3, 5.5, 12.7, 10.0, 13.7, 5.9, 17.6, 7…
$ grad                        <dbl> 13.5, 3.1, 5.1, 5.4, 9.8, 2.0, 8.7, 2.9, …
$ pov                         <dbl> 6.1, 19.5, 19.0, 8.8, 15.6, 25.5, 7.3, 8.…
$ hs_orless                   <dbl> 33.3, 64.6, 53.7, 45.4, 47.2, 61.4, 40.0,…
$ urc2013                     <dbl> 4, 6, 4, 4, 4, 1, 1, 1, 1, 1, 2, 3, 3, 3,…
$ aod                         <dbl> 37.363636, 34.818182, 36.000000, 43.41666…
$ state_Not.California        <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ city_Not.in.a.city          <dbl> 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0,…

Notice, it looks like we gained the log_prisec_length_25000 back with this recipe using the data with our changes to state and city.

Rows: 292
Columns: 37
$ id                          <fct> 1049.1003, 1073.101, 1073.2006, 1089.0014…
$ value                       <dbl> 11.659091, 13.114545, 12.228125, 12.23294…
$ fips                        <fct> 1049, 1073, 1073, 1089, 1103, 1121, 4013,…
$ lat                         <dbl> 34.28763, 33.54528, 33.38639, 34.68767, 3…
$ lon                         <dbl> -85.96830, -86.54917, -86.81667, -86.5863…
$ CMAQ                        <dbl> 8.534772, 9.303766, 10.235612, 9.343611, …
$ zcta_area                   <dbl> 203836235, 148994881, 56063756, 46963946,…
$ zcta_pop                    <dbl> 8300, 14212, 32390, 21297, 30545, 7713, 5…
$ imp_a500                    <dbl> 5.78200692, 0.06055363, 42.42820069, 23.2…
$ imp_a15000                  <dbl> 0.9730444, 2.9956557, 12.7487614, 10.3555…
$ county_area                 <dbl> 2012662359, 2878192209, 2878192209, 20761…
$ county_pop                  <dbl> 71109, 658466, 658466, 334811, 119490, 82…
$ log_dist_to_prisec          <dbl> 3.721489, 7.301545, 4.721755, 4.659519, 6…
$ log_pri_length_5000         <dbl> 8.517193, 9.683336, 10.737240, 8.517193, …
$ log_pri_length_25000        <dbl> 11.90959, 12.53777, 12.99669, 11.47391, 1…
$ log_prisec_length_500       <dbl> 7.310155, 6.214608, 7.528913, 8.760549, 6…
$ log_prisec_length_1000      <dbl> 8.585843, 7.600902, 9.342290, 9.543183, 8…
$ log_prisec_length_5000      <dbl> 10.214200, 11.262645, 11.713190, 11.48606…
$ log_prisec_length_10000     <dbl> 11.50894, 12.14101, 12.53899, 12.68440, 1…
$ log_prisec_length_25000     <dbl> 13.55979, 14.08915, 14.27363, 13.87170, 1…
$ log_nei_2008_pm10_sum_15000 <dbl> 3.3500444, 6.6241114, 5.8268686, 3.861625…
$ log_nei_2008_pm10_sum_25000 <dbl> 5.1719202, 7.5490587, 8.8205542, 5.219092…
$ popdens_county              <dbl> 35.330814, 228.777633, 228.777633, 161.26…
$ popdens_zcta                <dbl> 40.718962, 95.385827, 577.735106, 453.475…
$ nohs                        <dbl> 14.3, 7.2, 0.8, 1.2, 4.8, 16.7, 19.1, 6.4…
$ somehs                      <dbl> 16.7, 12.2, 2.6, 3.1, 7.8, 33.3, 15.6, 9.…
$ hs                          <dbl> 35.0, 32.2, 12.9, 15.1, 28.7, 37.5, 26.5,…
$ somecollege                 <dbl> 14.9, 19.0, 17.9, 20.5, 25.0, 12.5, 18.0,…
$ associate                   <dbl> 5.5, 6.8, 5.2, 6.5, 7.5, 0.0, 6.0, 8.8, 3…
$ bachelor                    <dbl> 7.9, 14.8, 35.5, 30.4, 18.2, 0.0, 10.6, 1…
$ grad                        <dbl> 5.8, 7.7, 25.2, 23.3, 8.0, 0.0, 4.1, 5.7,…
$ pov                         <dbl> 13.8, 10.5, 2.1, 5.2, 8.3, 18.8, 21.4, 14…
$ hs_orless                   <dbl> 66.0, 51.6, 16.3, 19.4, 41.3, 87.5, 61.2,…
$ urc2013                     <dbl> 6, 1, 1, 3, 4, 5, 1, 2, 5, 4, 4, 6, 6, 1,…
$ aod                         <dbl> 33.08333, 42.45455, 44.25000, 42.41667, 4…
$ state_Not.California        <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,…
$ city_Not.in.a.city          <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…

Great now we no longer have NA values! :)

Note: if you use the skip option for some of the preprocessing steps, be careful. juice() will show all of the results ignoring skip = TRUE. bake() will not necessarily conduct these steps on the new data.

Specifying the Model

So far we have used rsample to split the data and recipes to assign variable and to specify and prep our preprocessing (as well as to optionally extract the preprocessed data).

We will now use the parsnip package (which is similar to the previous caret package - and hence why it is named after the vegetable) to specify our model.

There are four aspects to define about our model:
1) the type of model (using specific functions in parsnip like rand_forest(), logistic_reg() etc.)
2) the mode of learning - classification or regression (using the set_mode() function)
3) the package or engine that we will use to implement the type of model selected (using the set_engine() function)
4) any arguments necessary for the model/package selected (using the set_args()function - for example the mtry = argument for random forest which is the number of variables to be used as options for splitting at each tree node)

We are going to start our analysis with a linear regression but we will demonstrate how we can try different models.

The first thing we do is define what type of model we would like to use. See here for modeling [options]in parsnip.

Linear Regression Model Specification (regression)

OK. So far all we have told parsnip is we want to use a linear regression… Let’s tell parsnip more about what we want.

We would like to use the ordinary least squares method to fit our linear regression. So we will tell parsnip that we want to use the lm package to implement our linear regression (there are many options actually- such as rstan glmnet, keras, and sparklyr). We will do so by using the set_engine() function of the parsnip package.

Linear Regression Model Specification (regression)

Computational engine: lm 

In some cases some packages can do either classification or prediction, so it is a good idea to specify which mode you intend to perform. You can do this with the set_mode() function of the parsnip package, by using either set_mode("classification") or set_mode("regression").

Linear Regression Model Specification (regression)

Computational engine: lm 

Fitting the Model: two ways - workflows and parsnip

To fit our model we can use the parsnip package and then assess our fit using the yardstick package.

However a newer package called workflows allows us to keep track of both our preprocessing steps and our model specification. It also allows us to implement fancier optimizations in an automated way and it is currently being developed to also handle post-processing operations, so it is good to learn about it!

So we will now create a workflow with the recipe (our preprocessing specifications) that we made and the model that we just specified.

First we use the workflow() function of the workflows package to create a workflow.

Then we add our recipe with the add_recipe() function and we add our model with the add_model() function of the workflows package.

Note: We do not need to actually prep our recipe before using workflows!

══ Workflow ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: linear_reg()

── Preprocessor ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
3 Recipe Steps

● step_dummy()
● step_corr()
● step_nzv()

── Model ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Linear Regression Model Specification (regression)

Computational engine: lm 

Ah, nice. Notice how it tells us about both our preprocessing steps and our model specifications.

Now we can prepare the recipe (estimate the parameters) and fit the model to our training data all at once. Printing the output we can see the coefficients of the model.

══ Workflow [trained] ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: linear_reg()

── Preprocessor ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
3 Recipe Steps

● step_dummy()
● step_corr()
● step_nzv()

── Model ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Call:
stats::lm(formula = formula, data = data)

Coefficients:
                (Intercept)                          lat  
                  2.265e+02                    3.639e-02  
                        lon                         CMAQ  
                  2.579e-02                    2.847e-01  
                  zcta_area                     zcta_pop  
                  3.638e-10                    7.880e-06  
                   imp_a500                   imp_a15000  
                  7.453e-03                   -1.140e-03  
                county_area                   county_pop  
                 -2.116e-11                   -2.156e-07  
         log_dist_to_prisec          log_pri_length_5000  
                  4.064e-02                   -1.842e-01  
       log_pri_length_25000        log_prisec_length_500  
                  7.936e-03                    2.572e-01  
     log_prisec_length_1000       log_prisec_length_5000  
                 -2.288e-02                    4.743e-01  
    log_prisec_length_10000      log_prisec_length_25000  
                 -1.410e-01                    4.658e-01  
log_nei_2008_pm10_sum_15000  log_nei_2008_pm10_sum_25000  
                  1.088e-01                    5.255e-02  
             popdens_county                 popdens_zcta  
                 -4.114e-05                   -1.816e-05  
                       nohs                       somehs  
                 -2.234e+00                   -2.270e+00  
                         hs                  somecollege  
                 -2.271e+00                   -2.274e+00  
                  associate                     bachelor  
                 -2.272e+00                   -2.277e+00  
                       grad                          pov  
                 -2.284e+00                    7.001e-03  
                  hs_orless                      urc2013  
                         NA                    2.153e-01  
                        aod         state_Not.California  
                  2.555e-02                   -3.445e+00  
         city_Not.in.a.city  
                  3.550e-01  

Otherwise we could have done this without the workflows package. Notice here we will used the processed training data (juiced_train) as opposed to the raw training data that we used with the workflow we created with workflows.

In this case, we actually need to write your model again! Recall that id and fips are ID variables and that values is our outcome of interest (the pm air pollution measure at each monitor).

Looking at model fit with broom

The broom package allows for an easy/tidy way to look at the fitted model:

tidy() grabs the coefficients from the model
glance() summarizes the model fit and gives us an idea about how well the model might perform augment() gives a 150 row observation level summary of the data and fit

These broom functions currently only work with parsnip objects not raw workflows objects. To use the tidy() function with workflows we need to first use the pull_workflow_fit() function.

# A tibble: 34 x 5
   term                     estimate    std.error statistic  p.value
   <chr>                       <dbl>        <dbl>     <dbl>    <dbl>
 1 state_Not.California -3.44        0.436            -7.91 1.45e-14
 2 CMAQ                  0.285       0.0430            6.61 8.90e-11
 3 aod                   0.0256      0.00575           4.45 1.06e- 5
 4 lon                   0.0258      0.00998           2.58 1.00e- 2
 5 county_pop           -0.000000216 0.0000000934     -2.31 2.14e- 2
 6 urc2013               0.215       0.101             2.13 3.35e- 2
 7 grad                 -2.28        1.20             -1.90 5.78e- 2
 8 bachelor             -2.28        1.20             -1.90 5.84e- 2
 9 somecollege          -2.27        1.20             -1.89 5.87e- 2
10 associate            -2.27        1.20             -1.89 5.90e- 2
# … with 24 more rows
# A tibble: 1 x 11
  r.squared adj.r.squared sigma statistic  p.value    df logLik   AIC   BIC
      <dbl>         <dbl> <dbl>     <dbl>    <dbl> <int>  <dbl> <dbl> <dbl>
1     0.433         0.399  2.08      12.7 1.02e-48    34 -1240. 2550. 2703.
# … with 2 more variables: deviance <dbl>, df.residual <int>
# A tibble: 584 x 42
   value   lat   lon  CMAQ zcta_area zcta_pop imp_a500 imp_a15000 county_area
   <dbl> <dbl> <dbl> <dbl>     <dbl>    <dbl>    <dbl>      <dbl>       <dbl>
 1  9.60  30.5 -87.9  8.10 190980522    27829   0.0173      1.44   4117521611
 2 10.8   33.3 -85.8  9.77 374132430     5103   1.97        0.336  1564252280
 3 11.2   34.8 -87.7  9.40  16716984     9042  19.2         5.25   1534877333
 4 12.4   34.0 -86.0  9.24 154069359    20045  16.5         5.16   1385618994
 5 10.5   31.2 -85.4  9.12 162685124    30217  19.1         4.74   1501737720
 6 15.6   33.6 -86.8 10.2   26929603     9010  41.8        17.5    2878192209
 7 12.4   33.3 -87.0 10.2  166239542    16140   1.70        4.30   2878192209
 8 11.1   33.5 -87.3  8.16 385566685     3699   0           0.162  3423328940
 9 14.6   33.5 -86.9 10.2   10636977    11458  43.6        15.6    2878192209
10 12.0   33.7 -86.7  9.30 150661846    21725   1.48        4.25   2878192209
# … with 574 more rows, and 33 more variables: county_pop <dbl>,
#   log_dist_to_prisec <dbl>, log_pri_length_5000 <dbl>,
#   log_pri_length_25000 <dbl>, log_prisec_length_500 <dbl>,
#   log_prisec_length_1000 <dbl>, log_prisec_length_5000 <dbl>,
#   log_prisec_length_10000 <dbl>, log_prisec_length_25000 <dbl>,
#   log_nei_2008_pm10_sum_15000 <dbl>, log_nei_2008_pm10_sum_25000 <dbl>,
#   popdens_county <dbl>, popdens_zcta <dbl>, nohs <dbl>, somehs <dbl>,
#   hs <dbl>, somecollege <dbl>, associate <dbl>, bachelor <dbl>, grad <dbl>,
#   pov <dbl>, hs_orless <dbl>, urc2013 <dbl>, aod <dbl>,
#   state_Not.California <dbl>, city_Not.in.a.city <dbl>, .fitted <dbl>,
#   .se.fit <dbl>, .resid <dbl>, .hat <dbl>, .sigma <dbl>, .cooksd <dbl>,
#   .std.resid <dbl>
[1] TRUE

OK, so we have fit our model on our training data, which means we have created a model to predict values of air pollution based on the predictors that we have included. Yay!

We can get a sense of the variable importance using the vip() function of the vip package.

Let’s take a look at the top 10 contributing variables:

Model Performance

Let’s take a look at how well our model fit our training data:

        1         2         3         4         5         6 
 9.461664 10.429189 11.795351 11.139746 10.863402 11.091857 
# A tibble: 6 x 8
  value .fitted .se.fit .resid   .hat .sigma    .cooksd .std.resid
  <dbl>   <dbl>   <dbl>  <dbl>  <dbl>  <dbl>      <dbl>      <dbl>
1  9.60    9.46   0.375  0.136 0.0324   2.09 0.00000433     0.0663
2 10.8    10.4    0.383  0.371 0.0338   2.09 0.0000338      0.181 
3 11.2    11.8    0.404 -0.583 0.0376   2.09 0.0000936     -0.285 
4 12.4    11.1    0.388  1.24  0.0346   2.08 0.000384       0.604 
5 10.5    10.9    0.426 -0.355 0.0418   2.09 0.0000388     -0.174 
6 15.6    11.1    0.379  4.50  0.0332   2.08 0.00486        2.20  
        1         2         3         4         5         6 
 9.461664 10.429189 11.795351 11.139746 10.863402 11.091857 
# A tibble: 6 x 8
  value .fitted .se.fit .resid   .hat .sigma    .cooksd .std.resid
  <dbl>   <dbl>   <dbl>  <dbl>  <dbl>  <dbl>      <dbl>      <dbl>
1  9.60    9.46   0.375  0.136 0.0324   2.09 0.00000433     0.0663
2 10.8    10.4    0.383  0.371 0.0338   2.09 0.0000338      0.181 
3 11.2    11.8    0.404 -0.583 0.0376   2.09 0.0000936     -0.285 
4 12.4    11.1    0.388  1.24  0.0346   2.08 0.000384       0.604 
5 10.5    10.9    0.426 -0.355 0.0418   2.09 0.0000388     -0.174 
6 15.6    11.1    0.379  4.50  0.0332   2.08 0.00486        2.20  
[1] TRUE

OK, so our fitted range appears to be smaller than the real values. We could probably do a bit better.

Let’s take a look at how well our model seems to be preforming more formally:

When assessing the performance of a model, the metrics we use depend on if we are preforming a classification or prediction also known as regression analysis. In our case we are performing a regression or prediction analysis and the metrics often used are: 1) mean absolute error (mae)
2) R squared error (rsq) This is also known as the coefficient of determination which is the squared correlation between truth and estimate
3) root mean squared error (rmse)

We can use the yardstick package to quickly calculate estimates for all of these values using the metrics() function. Alternatively if you only wanted one metric you could use the mae(), rsq(), or rmse() functions respectively. This is helpful to examine with our fitted training set values to see how well our model is performing and if we need to make adjustments.

# A tibble: 3 x 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 rmse    standard       2.02 
2 rsq     standard       0.433
3 mae     standard       1.49 
# A tibble: 1 x 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 mae     standard        1.49

Cross validation sample splitting

We will use the rsample package again in order to further implement what are called cross validation techniques. This is also called resampling or repartioning.

Note: we are not actually getting new samples from the underlying distribution so the term resampling is a bit of a misnomer.

Cross validation splits our training data into multiple training data sets to allow for a deeper assessment of the accuracy of the model.

Here is a visualization of the concept for cross validation/resampling/repartitioning from Max Kuhn:

Technically creating our testing and training set out of our original training data is sometimes considered a form of cross validation called the holdout method. As we just learned this can give us a better sense of the accuracy of our data in a more generalizable way.

However, we can do a better job of optimizing our model for accuracy if we also perform another type of cross validation on the newly defined training set that we just created. There are many cross validation methods and most can be easily implemented using rsamples package. We will use a very popular method called either k-fold or v-fold cross validation.

This method involves essentially preforming the hold out method iteratively with the training data.

First the training set is divided into k or v equally sized smaller pieces.

Then the model is trained on the model on k-1 or v-1 subsets of the data iteratively (removing a different v or k until all possible k-1 or v-1 sets have been evaluated) to get a sense of the performance of the model. This is really useful for fine tuning specific aspects of the model in a process called model tuning.

Here is a visualization of how the folds are created:

Note: People typically ignore spatial dependence with cross validation of air pollution monitoring data in the air pollution field, so we will do the same. However, it might make sense to leave out blocks of monitors rather than random individual monitors to help account for some spatial dependence.

The vfold_cv() function of the rsample package can be used to parse the training data into folds for k-fold/v-fold cross validation.

The v argument specifies the number of folds to create. The repeats argument specifies if any samples should be repeated across folds - default is FALSE The strata argument specifies a variable to stratify samples across folds (just like in initial_split()).

Again because these are created at random, we need to use the base set.seed() function in order to obtain the same results each time we knit this document. Generally speaking using 10 folds is good practice, but this depends on the variablity within your data. We are going to use 4 for the sake of expediency.

#  4-fold cross-validation 
# A tibble: 4 x 2
  splits            id   
  <list>            <chr>
1 <split [438/146]> Fold1
2 <split [438/146]> Fold2
3 <split [438/146]> Fold3
4 <split [438/146]> Fold4
NULL
NULL

Once the folds are created they can be used to evaluate performance by fitting the model to each of the resamples that we created:

We can fit the model to our cross validation folds using the fit_resamples() function of the tune package, by specifying our workflow object and the cross validation fold object we just created. See here for more information.

We can now take a look at various metrics of performance based on the fit of our cross validation “resamples”. To do this we will use the show_best() function of the tune package.

# A tibble: 1 x 5
  .metric .estimator  mean     n std_err
  <chr>   <chr>      <dbl> <int>   <dbl>
1 rmse    standard    2.18     4  0.0763

Tuning

Now let’s try some tuning.

Let’s take a closer look at how the air pollution monitor values vary with the location latitude and longitude.

We can see that there does not appear to be a single linear relationship for either of these predictors. Thus we might want to think about using splines or this(https://towardsdatascience.com/numerical-interpolation-natural-cubic-spline-52c1157b98ac) or just this(https://tidymodels.github.io/tune/articles/getting_started.html) or this(https://www.psych.mcgill.ca/misc/fda/ex-basis-b1.html) to model the relationship in our training data more closely. For example for the latitude plot (left) if we had 2 lines and one break-point called a knot around 40, with the first line having a positive slope and the second with a negative slope this would fit the data more similarly to the blue line shown in the figure.

We can tune for the number of knots by using a step function in the recipes package called step_ns() where ns stands for natural splines. In order to tune for the number of knots or degrees of freedom, we can set the deg_free argument to tune(). This is helpful, becuase we aren’t exactly sure how closely we should be following the relationship with the value and our longitude and latitude data in our training data to achieve good accuracy yet keep our model generalizable for other data.

This is when our cross validation methods become really handy. We can test out different values for the deg_free argument and see how our model performance varies across our training folds to try to find the optimal value.

We will update our recipe to add these steps. It is a good idea to do this for individual predictors because you can name each with the tune argument so that you can keep track of it later. We can see what we intend to tune with the parameters() function of the dials package.

See here for more information about implementing this in tidymodels.

Collection of 2 parameters for tuning

     id parameter type object class
 lon df       deg_free    nparam[+]
 lat df       deg_free    nparam[+]

Generally you could use the grid_*() functions of the dials package to create the different combinations of degrees of freedom to test for both variables to optimize the model. In our case we can visibly see that if we add more than say 4 or 5 degrees of freedom we will likely over-fit the data. So instead of using these functions we will create our own grid using the base seq() and expand.grid() functions.

  lon df lat df
1      1      1
2      3      1
3      5      1
4      1      3
5      3      3
6      5      3
7      1      5
8      3      5
9      5      5

Now we will tune this hyper-parameter (degrees of freedom) for both the lat and lon variables using our cross validation folds. To do this we will use the tune_grid() function of the tune package.

#  4-fold cross-validation 
# A tibble: 4 x 4
  splits            id    .metrics          .notes           
  <list>            <chr> <list>            <list>           
1 <split [438/146]> Fold1 <tibble [18 × 5]> <tibble [18 × 1]>
2 <split [438/146]> Fold2 <tibble [18 × 5]> <tibble [18 × 1]>
3 <split [438/146]> Fold3 <tibble [18 × 5]> <tibble [18 × 1]>
4 <split [438/146]> Fold4 <tibble [18 × 5]> <tibble [18 × 1]>
# A tibble: 18 x 7
   `lon df` `lat df` .metric .estimator  mean     n std_err
      <dbl>    <dbl> <chr>   <chr>      <dbl> <int>   <dbl>
 1        1        1 rmse    standard   2.18      4  0.0763
 2        1        1 rsq     standard   0.361     4  0.0486
 3        1        3 rmse    standard   2.13      4  0.0807
 4        1        3 rsq     standard   0.383     4  0.0388
 5        1        5 rmse    standard   2.13      4  0.0812
 6        1        5 rsq     standard   0.386     4  0.0403
 7        3        1 rmse    standard   2.10      4  0.0613
 8        3        1 rsq     standard   0.402     4  0.0296
 9        3        3 rmse    standard   2.05      4  0.0709
10        3        3 rsq     standard   0.428     4  0.0191
11        3        5 rmse    standard   2.03      4  0.0656
12        3        5 rsq     standard   0.439     4  0.0197
13        5        1 rmse    standard   2.11      4  0.0616
14        5        1 rsq     standard   0.397     4  0.0258
15        5        3 rmse    standard   2.05      4  0.0739
16        5        3 rsq     standard   0.427     4  0.0164
17        5        5 rmse    standard   2.02      4  0.0717
18        5        5 rsq     standard   0.442     4  0.0153
# A tibble: 1 x 7
  `lon df` `lat df` .metric .estimator  mean     n std_err
     <dbl>    <dbl> <chr>   <chr>      <dbl> <int>   <dbl>
1        5        5 rmse    standard    2.02     4  0.0717

Linear Regression Model with PCA

We can create another workflow to see how model performance compares using a different model. In this case we are going to perform something called Principal Component Analysis or PCA.

So what is PCA?

PCA is a widely used dimensionality reduction method (a form of unsupervised machine learning). It creates new variables that capture the most variation within the data, yet reduce the data down to just a number of principal components. It does so by transforming the data using orthogonal%20%3D%200.){target="_blank"} linear transformation. In other words, it creates new variables that are linear combinations of the variables within the data. Importantly these new variables are orthogonal, meaning that the new variables have zero covariance. In simpler terms, we are expressing unique types of variation within the data as new variables.

Check out this video for more information.

Let’s take a look to see what the step_pca function does to our predictors. To do so recall that we need to use the prep and juice functions of the recipes package on our recipe.

oper 1 step dummy [training] 
oper 2 step pca [training] 
The retained training set is ~ 0.13 Mb  in memory.
Rows: 584
Columns: 8
$ id    <fct> 1003.001, 1027.0001, 1033.1002, 1055.001, 1069.0003, 1073.0023,…
$ value <dbl> 9.597647, 10.800000, 11.212174, 12.375394, 10.508850, 15.591017…
$ fips  <fct> 1003, 1027, 1033, 1055, 1069, 1073, 1073, 1073, 1073, 1073, 107…
$ PC1   <dbl> -4120232815, -1570558844, -1534934869, -1388102571, -1504354268…
$ PC2   <dbl> -118909004, -346706197, 10140574, -129802253, -136385028, 23433…
$ PC3   <dbl> -72827.994, 7132.812, -56957.316, 45519.861, 36487.258, 448189.…
$ PC4   <dbl> -20385.63273, 1615.38773, -7187.37037, -15876.58640, -25852.952…
$ PC5   <dbl> -846.027447, 90.287809, 171.426032, -576.131718, -926.823714, -…

We still want to use the lm package for our regression so we can use the same model object as before:

Linear Regression Model Specification (regression)

Computational engine: lm 
══ Workflow ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: linear_reg()

── Preprocessor ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2 Recipe Steps

● step_dummy()
● step_pca()

── Model ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Linear Regression Model Specification (regression)

Computational engine: lm 

Remember that using workflows we don’t actually need to prep our recipe, we can just fit our model directly.

Fit the cross validation samples:

Look at the performance:

# A tibble: 2 x 5
  .metric .estimator   mean     n std_err
  <chr>   <chr>       <dbl> <int>   <dbl>
1 rmse    standard   2.76       4  0.271 
2 rsq     standard   0.0527     4  0.0184

And we can compare this with our previous performance:

# A tibble: 2 x 5
  .metric .estimator  mean     n std_err
  <chr>   <chr>      <dbl> <int>   <dbl>
1 rmse    standard   2.18      4  0.0763
2 rsq     standard   0.361     4  0.0486

So we can see that our performance isn’t quite as good - especially if we look at the rmse value.

Random Forest

Now for one last recipe, we are going to predict using a decision tree method called random forest.

A decision tree is a tool to partition data or anything really, based on a series of sequential (often binary) decisions, where the decisions are chosen based on their ability to optimally split the data.

Here you can see a simple example:

source

In the case of random forest, multiple decision trees are created - hence the name forest, and each tree is built using a random subset of the training data (with replacement) - hence the full name random forest. This random aspect helps to keep the algorithm from overfitting the data.

The mean of the predictions from each of the trees is used in the final output.

In our case, the random forest algorithm that we are working with does not work well when there are categorical variables with more than 53 levels, so we will need to remove the zcta variable.

The rand_forest() function of the parsnip package has three important arguments that act as an interface for the different possible engines to perform a random forest analysis:

  1. mtry The number of predictor or explanatory variables that will be randomly sampled as options at each split when creating the tree models. The default number for regression analyses is the number of predictors divided by 3.

  2. min_n - The minimum number of data points in a node that are required for the node to be split further.

  3. trees - the number of trees in the ensemble 10 and 3

Random Forest Model Specification (regression)

Main Arguments:
  mtry = 10
  min_n = 3
Random Forest Model Specification (regression)

Main Arguments:
  mtry = 10
  min_n = 3

Computational engine: randomForest 
══ Workflow ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: rand_forest()

── Preprocessor ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
7 Recipe Steps

● step_string2factor()
● step_rm()
● step_rm()
● step_rm()
● step_rm()
● step_corr()
● step_nzv()

── Model ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Random Forest Model Specification (regression)

Main Arguments:
  mtry = 10
  min_n = 3

Computational engine: randomForest 

Fitting the data with just parsnip and with the workflow:

══ Workflow [trained] ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: rand_forest()

── Preprocessor ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
7 Recipe Steps

● step_string2factor()
● step_rm()
● step_rm()
● step_rm()
● step_rm()
● step_corr()
● step_nzv()

── Model ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Call:
 randomForest(x = as.data.frame(x), y = y, mtry = ~10, nodesize = ~3) 
               Type of random forest: regression
                     Number of trees: 500
No. of variables tried at each split: 10

          Mean of squared residuals: 3.016711
                    % Var explained: 58.14

Let’s take a look at the top 10 contributing variables:

Interesting, in the previous model the CMAQ values were also important, however the variable about if the monitor was located in California or not was also very predictive.

Now let’s take a look at model performance by fitting the data using cross validation:

# A tibble: 2 x 5
  .metric .estimator  mean     n std_err
  <chr>   <chr>      <dbl> <int>   <dbl>
1 rmse    standard   1.79      4  0.105 
2 rsq     standard   0.580     4  0.0377

Now let’s compare the performance of this model with the others:

# A tibble: 2 x 5
  .metric .estimator  mean     n std_err
  <chr>   <chr>      <dbl> <int>   <dbl>
1 rmse    standard   2.18      4  0.0763
2 rsq     standard   0.361     4  0.0486
# A tibble: 1 x 7
  `lon df` `lat df` .metric .estimator  mean     n std_err
     <dbl>    <dbl> <chr>   <chr>      <dbl> <int>   <dbl>
1        5        5 rmse    standard    2.02     4  0.0717
# A tibble: 2 x 5
  .metric .estimator   mean     n std_err
  <chr>   <chr>       <dbl> <int>   <dbl>
1 rmse    standard   2.76       4  0.271 
2 rsq     standard   0.0527     4  0.0184

OK, so our first model had a mean rmse value of 2.18. The model with the lat/long degrees of freedom tuning had a mean rmse value of 2.02, thus showing some improvement. The PCA model had a mean rmse value of 2.76.

It looks like the random forest model had the lowest rmse value of 1.79.

If we tuned our random forest model based on the number of trees or the value for mtry (which is “The number of predictors that will be randomly sampled at each split when creating the tree models”), we might get a model with even better performance.

However, our cross validated mean rmse value of 1.79 is quite good because our range of true outcome values is much larger:3.4963303, 22.259123.

Final Model Performance Evaluation

Now that we have decided that we have reasonable performance with the training data, we could stop here and use the yardstick package (and tune if using workflows to fit our model) to evaluate performance with our testing data.

So now we will use our random forest model to predict values for the monitors in the testing data.

Using parsnip we would need to use the baked data testing data. With the workflows package, we could use the raw testing data.

Importantly, ID variables are not dealt with as nicely as with the workflows package so we would need to remove them. We did this above when created the processed training data for this model, the juiced_train data as well.

# A tibble: 292 x 1
   .pred
   <dbl>
 1 11.1 
 2 11.8 
 3 12.0 
 4 11.3 
 5 11.8 
 6 11.9 
 7 10.6 
 8 10.6 
 9  8.65
10  7.60
# … with 282 more rows
# A tibble: 292 x 5
   .pred value fips  county     id       
   <dbl> <dbl> <fct> <chr>      <fct>    
 1 11.1  11.7  1049  DeKalb     1049.1003
 2 12.0  13.1  1073  Jefferson  1073.101 
 3 11.6  12.2  1073  Jefferson  1073.2006
 4 11.3  12.2  1089  Madison    1089.0014
 5 11.5  11.4  1103  Morgan     1103.0011
 6 12.0  12.2  1121  Talladega  1121.0002
 7 10.8  10.9  4013  Maricopa   4013.4003
 8 10.7  10.6  4021  Pinal      4021.0001
 9  8.60 14.1  4023  Santa Cruz 4023.0004
10  7.59  5.83 4025  Yavapai    4025.2002
# … with 282 more rows
# A tibble: 3 x 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 rmse    standard       1.49 
2 rsq     standard       0.612
3 mae     standard       1.06 

Awesome! We can see that our rmse of 1.49 is quite similar with our testing data. We achieved quite good performance, which suggests that we would could predict other locations with more sparse monitoring based on our predictors with reasonable accuracy.

We could also use the last_fit() function of the tune package to look at performance if we chose to create a workflow using the workflows package.

# A tibble: 2 x 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 rmse    standard       1.49 
2 rsq     standard       0.607

We could check out test performance using the collect_metrics() function of the tune package.

# A tibble: 2 x 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 rmse    standard       1.49 
2 rsq     standard       0.607

Here you can see the predictions for the test set (the 292 rows with predictions out of the 876 original monitor values) also using the tune package with the collect_predictions() function.

# A tibble: 292 x 4
    id               .pred  .row value
    <chr>            <dbl> <int> <dbl>
  1 train/test split 11.1      4 11.7 
  2 train/test split 11.9     10 13.1 
  3 train/test split 11.8     12 12.2 
  4 train/test split 11.4     15 12.2 
  5 train/test split 11.5     19 11.4 
  6 train/test split 12.1     22 12.2 
  7 train/test split 10.6     30 10.9 
  8 train/test split 10.7     36 10.6 
  9 train/test split  8.54    39 14.1 
 10 train/test split  7.46    40  5.83
 11 train/test split  9.87    41  9.93
 12 train/test split 10.9     43 10.7 
 13 train/test split 10.2     49 10.5 
 14 train/test split 12.0     58 11.6 
 15 train/test split 13.3     59  9.54
 16 train/test split 12.2     60  9.54
 17 train/test split 11.1     63 11.9 
 18 train/test split 13.7     66 22.3 
 19 train/test split 10.5     70 10.2 
 20 train/test split 10.6     71  8.23
 21 train/test split  9.31    77  7.09
 22 train/test split 14.3     79 17.1 
 23 train/test split 13.5     83 16.1 
 24 train/test split 12.8     84 11.8 
 25 train/test split 13.5     86 15.0 
 26 train/test split 12.8     88 14.2 
 27 train/test split 11.3     97 10.4 
 28 train/test split 12.4     98 11.2 
 29 train/test split  9.50   100 14.2 
 30 train/test split 12.0    101 13.3 
 31 train/test split 10.1    102  8.25
 32 train/test split  8.37   103  6.98
 33 train/test split 14.0    104 16.4 
 34 train/test split 13.4    105 18.2 
 35 train/test split 12.6    107 12.0 
 36 train/test split 13.0    108 13.3 
 37 train/test split 11.1    116 13.4 
 38 train/test split  8.40   123  7.61
 39 train/test split  8.33   126 10.4 
 40 train/test split  9.29   131 15.3 
 41 train/test split 13.1    136 13.0 
 42 train/test split 10.1    138 10.4 
 43 train/test split  9.18   141 10.0 
 44 train/test split 12.5    142 10.6 
 45 train/test split  8.55   145  7.69
 46 train/test split  8.53   147  7.99
 47 train/test split  8.00   155  7.34
 48 train/test split 11.1    160 11.8 
 49 train/test split 10.0    163 10.5 
 50 train/test split 11.4    166 11.5 
 51 train/test split 11.4    169 10.6 
 52 train/test split 10.2    170 11.6 
 53 train/test split 10.7    171 10.1 
 54 train/test split 11.8    178 12.2 
 55 train/test split 12.0    181 11.7 
 56 train/test split  9.63   182  7.26
 57 train/test split 10.6    184  9.91
 58 train/test split  8.76   188  8.13
 59 train/test split 10.2    189  7.82
 60 train/test split  9.45   194  8.23
 61 train/test split  9.02   195  7.02
 62 train/test split  8.21   203  6.08
 63 train/test split  9.12   205  8.08
 64 train/test split  9.94   207  8.10
 65 train/test split  9.38   208  7.55
 66 train/test split  9.79   210  8.00
 67 train/test split 12.5    211 12.3 
 68 train/test split 11.6    212 12.2 
 69 train/test split 11.8    214 11.5 
 70 train/test split 11.4    215 12.3 
 71 train/test split 13.0    216 13.8 
 72 train/test split 12.0    218 13.1 
 73 train/test split 11.8    221 12.9 
 74 train/test split 11.6    227 11.9 
 75 train/test split 11.7    228 11.7 
 76 train/test split 11.9    231 12.6 
 77 train/test split 12.5    234 13.7 
 78 train/test split  8.59   243  6.25
 79 train/test split 10.4    248 11.0 
 80 train/test split 12.1    249 12.6 
 81 train/test split 11.8    250 11.8 
 82 train/test split 12.4    251 12.2 
 83 train/test split 12.3    254 12.9 
 84 train/test split 12.0    258 11.3 
 85 train/test split 12.4    260 13.2 
 86 train/test split 10.7    262 12.4 
 87 train/test split 11.0    265 10.4 
 88 train/test split 12.2    270 11.9 
 89 train/test split 11.5    276 10.4 
 90 train/test split 11.6    280 11.1 
 91 train/test split 12.2    281 11.7 
 92 train/test split 12.1    284 11.7 
 93 train/test split 12.7    291 12.6 
 94 train/test split 11.3    293 11.4 
 95 train/test split 12.0    294 11.5 
 96 train/test split 12.3    296 11.9 
 97 train/test split 12.5    297 12.5 
 98 train/test split 12.3    298 13.9 
 99 train/test split 11.7    303 11.2 
100 train/test split 13.1    305 15.1 
101 train/test split 12.6    307 13.1 
102 train/test split 12.8    309 13.3 
103 train/test split 11.4    313 11.8 
104 train/test split 12.1    319 11.9 
105 train/test split 10.4    326 10.3 
106 train/test split  9.34   328  8.81
107 train/test split 11.9    335 11.2 
108 train/test split  8.68   338  9.85
109 train/test split 10.5    343  9.63
110 train/test split 10.6    344  9.47
111 train/test split 10.5    345  9.39
112 train/test split 11.0    350 12.5 
113 train/test split 12.2    358 12.1 
114 train/test split 12.0    361 11.7 
115 train/test split 13.5    362 13.2 
116 train/test split 13.7    363 13.4 
117 train/test split 12.4    365 12.7 
118 train/test split 11.4    371 12.5 
119 train/test split 11.8    375 11.4 
120 train/test split 10.3    378  9.57
121 train/test split 10.6    379  9.15
122 train/test split 11.4    380  9.28
123 train/test split 10.2    382  9.23
124 train/test split  8.08   389  5.58
125 train/test split 12.9    390 12.7 
126 train/test split 11.5    395  9.64
127 train/test split 11.8    397 12.2 
128 train/test split 12.4    400 12.2 
129 train/test split 13.0    403 14.3 
130 train/test split  9.41   405  9.96
131 train/test split 10.0    413  8.70
132 train/test split 11.3    417  9.82
133 train/test split 10.7    421  9.64
134 train/test split 10.0    424 10.8 
135 train/test split 11.0    427 10.1 
136 train/test split 11.7    428  9.87
137 train/test split 11.3    429 11.2 
138 train/test split 11.4    430 11.1 
139 train/test split 11.3    431 10.6 
140 train/test split 10.5    432  9.93
141 train/test split  8.66   434  7.61
142 train/test split 11.3    440 11.1 
143 train/test split 11.3    441 11.4 
144 train/test split 12.3    442 11.9 
145 train/test split 12.5    444 11.9 
146 train/test split 12.6    449 11.8 
147 train/test split 12.6    450 12.3 
148 train/test split 10.5    456 10.1 
149 train/test split  8.14   457  7.01
150 train/test split 10.8    460 11.1 
151 train/test split 10.9    461 10.9 
152 train/test split  8.47   463  6.70
153 train/test split 10.5    468 10.7 
154 train/test split 11.0    469 11.8 
155 train/test split  9.98   471 13.0 
156 train/test split 11.1    474 12.1 
157 train/test split 10.3    475 10.1 
158 train/test split 11.1    476 13.1 
159 train/test split 11.3    478 11.8 
160 train/test split 11.6    479 11.6 
161 train/test split 10.3    480 12.0 
162 train/test split  9.70   482 10.1 
163 train/test split 10.4    484 10.8 
164 train/test split 11.8    485 12.5 
165 train/test split 11.7    486 11.4 
166 train/test split 12.2    488 12.2 
167 train/test split 12.7    491 12.7 
168 train/test split  8.35   495  9.26
169 train/test split  6.84   497  5.34
170 train/test split  6.46   499  6.89
171 train/test split  7.49   501  7.32
172 train/test split  7.83   508  7.26
173 train/test split 10.3    510  8.83
174 train/test split  8.83   511  7.69
175 train/test split 10.1    512  7.87
176 train/test split 11.0    518  9.01
177 train/test split  7.75   522  6.68
178 train/test split 12.4    529 11.5 
179 train/test split 12.6    534 11.9 
180 train/test split 12.6    538 13.2 
181 train/test split 11.1    540 10.0 
182 train/test split 11.8    541 10.9 
183 train/test split 11.3    542  9.43
184 train/test split 10.1    543  8.84
185 train/test split 12.3    548 11.9 
186 train/test split  7.08   552  6.22
187 train/test split 10.4    561  8.23
188 train/test split 12.2    564 11.7 
189 train/test split 12.1    569 11.9 
190 train/test split 12.2    573 13.2 
191 train/test split 11.3    574  9.67
192 train/test split 12.2    577 11.0 
193 train/test split 12.3    578 12.0 
194 train/test split 10.8    585  9.31
195 train/test split 11.6    587 12.7 
196 train/test split 10.9    588 11.1 
197 train/test split 11.5    592 11.4 
198 train/test split 11.4    595 12.3 
199 train/test split 12.2    596 12.4 
200 train/test split 10.9    597 11.6 
201 train/test split 11.4    598 12.5 
202 train/test split  9.68   599 11.7 
203 train/test split 10.1    600 10.5 
204 train/test split 11.6    601 10.5 
205 train/test split 10.8    602 11.6 
206 train/test split 11.9    605 13.1 
207 train/test split 10.4    607  9.86
208 train/test split 11.3    608 11.0 
209 train/test split 11.9    613 12.9 
210 train/test split 10.9    623 10.7 
211 train/test split 11.8    627 11.7 
212 train/test split 12.6    629 10.8 
213 train/test split 12.9    634 11.9 
214 train/test split 11.2    638 11.6 
215 train/test split 13.3    642 14.4 
216 train/test split 12.3    643 13.3 
217 train/test split 12.9    645 14.5 
218 train/test split 13.1    646 14.5 
219 train/test split 12.4    649 13.2 
220 train/test split 11.5    658 12.2 
221 train/test split 11.6    659 12.0 
222 train/test split 11.7    660 12.0 
223 train/test split 12.4    661 13.4 
224 train/test split 11.8    665 13.2 
225 train/test split 12.2    666 12.0 
226 train/test split  8.80   667  9.68
227 train/test split 11.2    670 10.3 
228 train/test split 11.3    675 11.7 
229 train/test split 11.1    676 11.4 
230 train/test split  8.05   678 11.7 
231 train/test split  8.45   682 13.3 
232 train/test split  8.52   687 13.1 
233 train/test split 12.6    696 17.1 
234 train/test split 11.9    697 10.8 
235 train/test split 12.5    701 13.9 
236 train/test split 11.0    707 13.0 
237 train/test split 12.4    708 13.2 
238 train/test split 13.0    719 13.4 
239 train/test split  9.69   726  6.61
240 train/test split 10.1    727  9.24
241 train/test split 11.2    733 11.1 
242 train/test split 12.1    736 12.6 
243 train/test split 10.9    737 12.2 
244 train/test split  9.67   740  9.10
245 train/test split 10.7    743 11.8 
246 train/test split 11.6    744 12.0 
247 train/test split  8.24   747  9.59
248 train/test split 12.3    754 12.3 
249 train/test split  9.21   757  9.95
250 train/test split  9.99   758  8.71
251 train/test split  5.85   760  5.68
252 train/test split 11.9    763 10.8 
253 train/test split 10.5    773 10.2 
254 train/test split 10.3    775 12.0 
255 train/test split 10.6    776 11.0 
256 train/test split 10.5    777  8.94
257 train/test split 11.6    780 10.3 
258 train/test split  9.26   782  8.87
259 train/test split  7.89   784  8.20
260 train/test split  8.88   787 10.6 
261 train/test split  8.94   794  7.90
262 train/test split  8.95   795  8.23
263 train/test split  9.23   796  9.86
264 train/test split  9.03   798  7.33
265 train/test split 12.2    803 12.0 
266 train/test split 12.1    806 11.1 
267 train/test split 11.9    808 11.8 
268 train/test split 11.9    810 10.8 
269 train/test split 11.1    811 10.5 
270 train/test split 12.0    816 11.6 
271 train/test split 10.7    817 10.2 
272 train/test split  9.33   822  8.39
273 train/test split  8.97   826  7.35
274 train/test split  9.26   827  8.40
275 train/test split 12.7    832 14.2 
276 train/test split 12.6    833 14.3 
277 train/test split 11.4    835 12.6 
278 train/test split 11.7    840 12.6 
279 train/test split 11.8    841 12.8 
280 train/test split  7.53   844  6.38
281 train/test split 10.5    846 12.4 
282 train/test split 10.4    847 10.6 
283 train/test split  7.87   848  6.96
284 train/test split  9.94   849 12.7 
285 train/test split 12.6    853 12.8 
286 train/test split 10.2    860 10.8 
287 train/test split  7.49   862 10.2 
288 train/test split  8.02   865  5.25
289 train/test split  6.38   866  5.85
290 train/test split  6.63   868  3.50
291 train/test split  6.98   871  7.05
292 train/test split  6.02   872  7.82

Data Visualization

Our main question for this case study was:

  1. Can we predict annual average air pollution concentrations at the granularity of zip code regional levels using predictors such as data about population density, urbanization, road density, as well as, satellite pollution data and chemical modeling data?

We have indeed created a model that can predict fine particulate matter air pollution levels based on our predictor variables.

Now let’s make a plot of our predicted values and the true values.

First, let’s start by making a plot of our monitors:

We will use the following packages to create a map of the US: 1)sf 2)maps 2)rnaturalearth 3)rgeos

According to this link on wikipedia, these are the latitude and longitude bounds of the continental US.

top = 49.3457868 # north lat left = -124.7844079 # west long right = -66.9513812 # east long bottom = 24.7433195 # south lat

We will start with getting an outline of the US with the ne_countries() function of the rnaturalearth package.

Now let’s add county lines.

County graphical data is available from the maps package. The sf package which is short for simple features creates a data frame about this graphical data so that we can work with it.

Now let’s add a fill at the county level for the true monitor values of air pollution:

Simple feature collection with 6 features and 1 field
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -88.01778 ymin: 30.24071 xmax: -85.06131 ymax: 34.2686
CRS:            EPSG:4326
               ID                           geom
1 alabama,autauga MULTIPOLYGON (((-86.50517 3...
2 alabama,baldwin MULTIPOLYGON (((-87.93757 3...
3 alabama,barbour MULTIPOLYGON (((-85.42801 3...
4    alabama,bibb MULTIPOLYGON (((-87.02083 3...
5  alabama,blount MULTIPOLYGON (((-86.9578 33...
6 alabama,bullock MULTIPOLYGON (((-85.66866 3...

Now let’s do the same with our predicted values.

Let’s grab both the testing and training fitted values so that we have as much data as possible. In this case, the output structure for the training data fit is slightly different using randomForest. The fitted values are called predicted and the broom functions like tidy() and augment() will not work. So we will manually grab the fitted training data values.

# A tibble: 292 x 5
   .pred value fips  county     id       
   <dbl> <dbl> <fct> <chr>      <fct>    
 1 11.1  11.7  1049  DeKalb     1049.1003
 2 12.0  13.1  1073  Jefferson  1073.101 
 3 11.6  12.2  1073  Jefferson  1073.2006
 4 11.3  12.2  1089  Madison    1089.0014
 5 11.5  11.4  1103  Morgan     1103.0011
 6 12.0  12.2  1121  Talladega  1121.0002
 7 10.8  10.9  4013  Maricopa   4013.4003
 8 10.7  10.6  4021  Pinal      4021.0001
 9  8.60 14.1  4023  Santa Cruz 4023.0004
10  7.59  5.83 4025  Yavapai    4025.2002
# … with 282 more rows

quartz_off_screen 
                2 

Summary

Let’s review everything:

We have explored gravimetric monitoring data of fine particulate matter air pollution. We have utilized the tidymodels ecosystem of packages to predict monitor values using a variety of predictors, also known as explanatory variables, including satellite data, road density data, and population density, among others. Our model could now be extended to be used to predict pollution levels in areas poor monitoring, to help identify regions where populations maybe especially at risk for the health effects of air pollution.

We learned that there are two major types of what is called supervised machine learning: prediction and classification. We learned that prediction is used when the outcome variable is numeric and classification is performed when the outcome variable is categorical.

We performed the major steps of machine learning that we introduced in the beginning of the data analysis:

  1. Data exploration

We used a packages like skimr, summarytools, corrplot, ggcorrplot, and GGally to better understand our data. These packages gave can tell us how many missing values each variable has (if any), the class of each variable, the distribution of values for each variable, the sparsity of each variable, and the level of correlation between variables.

  1. Data splitting

We used the rsample package to first perform an initial split of our data into two pieces: a training set and a testing set. The training set was used to optimize the model, while the testing set was used only to evaluate the performance of our final model. We also used the rsample package to create cross validation subsets of our training data. This allowed us to better assess the performance of our tested models using our training data.

  1. Variable assignment and preprocessing

We used the recipes package to assign variable roles (such as outcome, predictor, and id variable). We also used this package to create a recipe for preprocessing our training and testing data. This involved steps such as: step_dummy to create dummy numeric encodings of our categorical variables, step_corr to remove highly correlated variables, step_nzv to remove near zero variance variables that would contribute little to our model and potentially add noise. We learned that once our recipe was created and prepped using prep()we could extract the pre-processed training data using juice() or our pre-processed testing data using bake(). We also learned that if we used the newer workflows package that we did not need to the prep(), juice(), or bake() functions, but that it is still useful to know how to do so if we want to look at our data and how the recipe is influencing it more deeply.

  1. Model specification, fitting, tuning and performance evaluation using the training data

We learned that the model needs to first be fit to the training data. We learned that in both classification and prediction, the model is fit to the training data and the explanatory variables are used to estimate numeric values (in the case of prediction) or categorical values (in the case of classification) of the outcome variable of interest. We learned that we specify the model and its specifications using the parnsip package and that we also use this package to fit the model using the fit() function. We learned that we if just use parsnip to fit the model, then we need to use the pre-processed training data (output from juice()). We learned that we can use the raw training data if we use the workflows package to create a workflow that pre-processes our data for us.

We learned that if the model fits well than the estimated values will be very similar to the true outcome variable values in our training data. We learned that we can assess model performance using the yardstick package and the metrics() function. We also learned that we can use subsets of our training data (which we created with the rsample package) to perform cross validation to get a better estimate about the performance of our model using our training data, as we want our results to be generalizable and to perform well with other data, not just our training data. We used the fit_resamples() function of the tune package to fit our model on our different training data subsets and the collect_metrics() function (also of the tune package) to evaluate model performance using these subsets. We also learned that we can potentially improve model performance by tuning aspects about the model called hyper-parameters to determine the best option for model performance. We learned that we can do this using the tune and dials packages and evaluating the performance of our model with the different hyper-parameter options and our training data subsets that we used for cross validation. After we tested several different methods to model our data, we compared them to choose the best performing model as our final model.

  1. Overall model performance evaluation

Once we chose our final model, we evaluated the final model performance using the testing data. This gives us a better estimate about how well the model will predict or classify the outcome variable of interest with new independent data. Ideally one would also perform an evaluation with independent data to provide a sense of how generalizable the model is to other data sources.

We first fit our model to our testing data using either just parsnip and the pre-processed testing data (using the bake() recipes function), or our raw testing data if we used a workflow. We used the same performance evaluation functions (yardstick::metrics() and tune::collect_metrics()(when using cross validation)). We also learned how we can use the last_fit() function of the tune package if we used a workflow to get the test data performance using the initial data and the testing/training split information.

Analyses like the one in our case study are important for defining which groups could benefit the most from interventions, education, and policy changes when attempting to mitigate public health challenges. You can see in this article that many additional considerations would be involved to adequately understand the data enough to recommend policy changes.

Suggested Homework

Students can predict air pollution monitor values using a different algorithm and provide an explanation for how that algorithm works and why it may be a good choice for modeling this data.

Session info


R version 4.0.1 (2020-06-06)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Mojave 10.14.5

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] cowplot_1.0.0       rgeos_0.5-3         sp_1.4-2           
 [4] rnaturalearth_0.1.0 maps_3.3.0          sf_0.9-3           
 [7] lwgeom_0.2-4        tidyr_1.1.0         stringr_1.4.0      
[10] randomForest_4.6-14 vip_0.2.2           yardstick_0.0.6    
[13] workflows_0.1.1     tune_0.1.0          tibble_3.0.1       
[16] rsample_0.0.7       recipes_0.1.12      purrr_0.3.4        
[19] parsnip_0.1.1       infer_0.5.1         dials_0.0.7        
[22] scales_1.1.1        broom_0.5.6         tidymodels_0.1.0   
[25] GGally_2.0.0        ggcorrplot_0.1.3    ggplot2_3.3.1      
[28] RColorBrewer_1.1-2  corrplot_0.84       magrittr_1.5       
[31] summarytools_0.9.6  skimr_2.1.1         dplyr_1.0.0        
[34] readr_1.3.1         knitr_1.28          here_0.1           

loaded via a namespace (and not attached):
  [1] utf8_1.1.4              tidyselect_1.1.0        lme4_1.1-23            
  [4] htmlwidgets_1.5.1       grid_4.0.1              pROC_1.16.2            
  [7] munsell_0.5.0           codetools_0.2-16        units_0.6-6            
 [10] statmod_1.4.34          DT_0.13                 future_1.17.0          
 [13] miniUI_0.1.1.1          withr_2.2.0             colorspace_1.4-1       
 [16] highr_0.8               rstudioapi_0.11         stats4_4.0.1           
 [19] bayesplot_1.7.2         listenv_0.8.0           labeling_0.3           
 [22] rstan_2.19.3            repr_1.1.0              rnaturalearthdata_0.1.0
 [25] DiceDesign_1.8-1        farver_2.0.3            rprojroot_1.3-2        
 [28] vctrs_0.3.1             generics_0.0.2          ipred_0.9-9            
 [31] xfun_0.14               R6_2.4.1                markdown_1.1           
 [34] rstanarm_2.19.3         lhs_1.0.2               reshape_0.8.8          
 [37] assertthat_0.2.1        promises_1.1.1          nnet_7.3-14            
 [40] gtable_0.3.0            globals_0.12.5          processx_3.4.2         
 [43] timeDate_3043.102       rlang_0.4.6             splines_4.0.1          
 [46] rapportools_1.0         checkmate_2.0.0         inline_0.3.15          
 [49] yaml_2.2.1              reshape2_1.4.4          tidytext_0.2.4         
 [52] threejs_0.3.3           crosstalk_1.1.0.1       backports_1.1.7        
 [55] httpuv_1.5.4            rsconnect_0.8.16        tokenizers_0.2.1       
 [58] tools_4.0.1             lava_1.6.7              tcltk_4.0.1            
 [61] ellipsis_0.3.1          ggridges_0.5.2          Rcpp_1.0.4.6           
 [64] plyr_1.8.6              base64enc_0.1-3         classInt_0.4-3         
 [67] ps_1.3.3                prettyunits_1.1.1       rpart_4.1-15           
 [70] zoo_1.8-8               furrr_0.1.0             magick_2.3             
 [73] colourpicker_1.0        GPfit_1.0-8             SnowballC_0.7.0        
 [76] matrixStats_0.56.0      tidyposterior_0.0.3     hms_0.5.3              
 [79] shinyjs_1.1             mime_0.9                evaluate_0.14          
 [82] xtable_1.8-4            tidypredict_0.4.5       shinystan_2.5.0        
 [85] gridExtra_2.3           rstantools_2.1.0        compiler_4.0.1         
 [88] KernSmooth_2.23-17      crayon_1.3.4            minqa_1.2.4            
 [91] StanHeaders_2.21.0-3    htmltools_0.4.0         mgcv_1.8-31            
 [94] later_1.1.0.1           lubridate_1.7.8         DBI_1.1.0              
 [97] MASS_7.3-51.6           boot_1.3-25             Matrix_1.2-18          
[100] cli_2.0.2               pryr_0.1.4              parallel_4.0.1         
[103] gower_0.2.1             igraph_1.2.5            pkgconfig_2.0.3        
[106] foreach_1.5.0           dygraphs_1.1.1.6        hardhat_0.1.3          
[109] prodlim_2019.11.13      janeaustenr_0.1.5       callr_3.4.3            
[112] digest_0.6.25           rmarkdown_2.2           shiny_1.4.0.2          
[115] gtools_3.8.2            nloptr_1.2.2.1          lifecycle_0.2.0        
[118] nlme_3.1-148            jsonlite_1.6.1          viridisLite_0.3.0      
[121] fansi_0.4.1             pillar_1.4.4            lattice_0.20-41        
[124] loo_2.2.0               fastmap_1.0.1           pkgbuild_1.0.8         
[127] survival_3.1-12         glue_1.4.1              xts_0.12-0             
[130] shinythemes_1.1.2       iterators_1.0.12        pander_0.6.3           
[133] class_7.3-17            stringi_1.4.6           e1071_1.7-3            
LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXMgOiBQcmVkaWN0aW5nIEFubnVhbCBBaXIgUG9sbHV0aW9uICIKY3NzOiBzdHlsZS5jc3MKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBzZWxmX2NvbnRhaW5lZDogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKCi0tLQo8c3R5bGU+CiNUT0MgewogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvL2ltZy9sb2dvLmpwZyIpOwogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsKICBwYWRkaW5nLXRvcDogMjQwcHggIWltcG9ydGFudDsKICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Owp9Cjwvc3R5bGU+CgoKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgb3V0LndpZHRoID0gJzkwJScpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShrbml0cikKYGBgCgoKIyMjIyB7Lm91dGxpbmUgfQpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiODAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIm1haW5fcGxvdF9tYXBzLnBuZyIpKQpgYGAKCiMjIyMKCiMjIHsuZGlzY2xhaW1lcl9ibG9ja30KCioqRGlzY2xhaW1lcioqOiBUaGUgcHVycG9zZSBvZiB0aGUgW09wZW4gQ2FzZSBTdHVkaWVzXShodHRwczovL29wZW5jYXNlc3R1ZGllcy5naXRodWIuaW8pe3RhcmdldD0iX2JsYW5rIn0gcHJvamVjdCBpcyAqKnRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdmFyaW91cyBkYXRhIHNjaWVuY2UgbWV0aG9kcywgdG9vbHMsIGFuZCBzb2Z0d2FyZSBpbiB0aGUgY29udGV4dCBvZiBtZXNzeSwgcmVhbC13b3JsZCBkYXRhKiouIEEgZ2l2ZW4gY2FzZSBzdHVkeSBkb2VzIG5vdCBjb3ZlciBhbGwgYXNwZWN0cyBvZiB0aGUgcmVzZWFyY2ggcHJvY2VzcywgaXMgbm90IGNsYWltaW5nIHRvIGJlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHdheSB0byBhbmFseXplIGEgZ2l2ZW4gZGF0YSBzZXQsIGFuZCBzaG91bGQgbm90IGJlIHVzZWQgaW4gdGhlIGNvbnRleHQgb2YgbWFraW5nIHBvbGljeSBkZWNpc2lvbnMgd2l0aG91dCBleHRlcm5hbCBjb25zdWx0YXRpb24gZnJvbSBzY2llbnRpZmljIGV4cGVydHMuIAoKIyMgTW90aXZhdGlvbgpBIHZhcmlldHkgb2YgZGlmZmVyZW50IHNvdXJjZXMgY29udHJpYnV0ZSBkaWZmZXJlbnQgdHlwZXMgb2YgcG9sbHV0YW50cyB0byB3aGF0IHdlIGNhbGwgYWlyIHBvbGx1dGlvbi4gClNvbWUgc291cmNlcyBhcmUgbmF0dXJhbCB3aGlsZSBvdGhlcnMgYXJlIGFudGhyb3BvZ2VuaWMgKGh1bWFuIGRlcml2ZWQpOgoKPHAgYWxpZ249ImNlbnRlciI+CiAgPGltZyB3aWR0aD0iNjAwIiBzcmM9Imh0dHBzOi8vd3d3Lm5wcy5nb3Yvc3ViamVjdHMvYWlyL2ltYWdlcy9Tb3VyY2VzX0dyYXBoaWNfSHVnZS5qcGc/bWF4d2lkdGg9MTIwMCZtYXhoZWlnaHQ9MTIwMCZhdXRvcm90YXRlPWZhbHNlIj4KPC9wPgoKIyMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vdXJsP3NhPWkmdXJsPWh0dHBzJTNBJTJGJTJGd3d3Lm5wcy5nb3YlMkZzdWJqZWN0cyUyRmFpciUyRnNvdXJjZXMuaHRtJnBzaWc9QU92VmF3MnY3QVZ4U0Y4WlNBUEVoTnVkVnRiTiZ1c3Q9MTU4NTc3MDk2NjIxNzAwMCZzb3VyY2U9aW1hZ2VzJmNkPXZmZSZ2ZWQ9MENBSVFqUnhxRndvVENQRE42NnFfeGVnQ0ZRQUFBQUFkQUFBQUFCQUQpXXt0YXJnZXQ9Il9ibGFuayJ9CgojIyMjIE1ham9yIHR5cGVzIG9mIGFpciBwb2xsdXRhbnRzCgoxKSAqKkdhc2VvdXMqKiAtIENhcmJvbiBNb25veGlkZSAoQ08pLCBPem9uZSAoT34zfiksIE5pdHJvZ2VuIE94aWRlcyhOTywgTk9+Mn4pLCBTdWxwaGVyIERpb3hpZGUgKFNPfjJ+KQoyKSAqKlBhcnRpY3VsYXRlKiogLSBzbWFsbCBsaXF1aWRzIGFuZCBzb2xpZHMgc3VzcGVuZGVkIGluIHRoZSBhaXIgKGluY2x1ZGVzIGxlYWQtIGNhbiBpbmNsdWRlIGNlcnRhaW4gdHlwZXMgb2YgZHVzdCkKMykgKipEdXN0KiogLSBzbWFsbCBzb2xpZHMgKGxhcmdlciB0aGFuIHBhcnRpY3VsYXRlcykgdGhhdCBjYW4gYmUgc3VzcGVuZGVkIGluIHRoZSBhaXIgZm9yIHNvbWUgdGltZSBidXQgZXZlbnR1YWxseSBzZXR0bGUKNCkgKipCaW9sb2dpY2FsKiogLSBwb2xsZW4sIGJhY3RlcmlhLCB2aXJ1c2VzLCBtb2xkIHNwb3JlcwoKU2VlIFtoZXJlXSlodHRwOi8vd3d3LnJlZGxvZ2Vudi5jb20vd29ya2VyLXNhZmV0eS9wYXJ0LTEtZHVzdC1hbmQtcGFydGljdWxhdGUtbWF0dGVyKSBmb3IgbW9yZSBkZXRhaWwgb24gdGhlIHR5cGVzIG9mIHBvbGx1dGFudHMgaW4gdGhlIGFpci4KCgojIyMjIFBhcnRpY3VsYXRlIHBvbGx1dGlvbiAKCkFpciBwb2xsdXRpb24gcGFydGljdWxhdGVzIGFyZSBnZW5lcmFsbHkgZGVzY3JpYmVkIGJ5IHRoZWlyICoqc2l6ZSoqLgoKVGhlcmUgYXJlIDMgbWFqb3IgY2F0ZWdvcmllczoKCjEpICoqTGFyZ2UgQ29hcnNlKiogUGFydGljdWxhdGUgTWF0ZXIgLSBoYXMgZGlhbWV0ZXIgb2YgPjEwIG1pY3JvbWV0ZXJzICgxMCDCtW0pIAoKMikgKipDb2Fyc2UqKiBQYXJ0aWN1bGF0ZSBNYXRlciAoY2FsbGVkICoqUE1+MTAtMi41fioqKSAtIGhhcyBkaWFtZXRlciBvZiBiZXR3ZWVuIDIuNSDCtW0gYW5kIDEwIMK1bQoKMykgKipGaW5lKiogUGFydGljdWxhdGUgTWF0ZXIgKGNhbGxlZCAqKlBNfjIuNX4qKikgLSBoYXMgZGlhbWV0ZXIgb2YgPCAyLjUgwrVtIAoKKipQTX4xMH4qKiBpbmNsdWRlcyBhbnkgcGFydGljdWxhdGUgbWF0ZXIgPDEwIMK1bSAoYm90aCBjb2Fyc2UgYW5kIGZpbmUgcGFydGljdWxhdGUgbWF0ZXIpCgpIZXJlIHlvdSBjYW4gc2VlIGhvdyB0aGVzZSBzaXplcyBjb21wYXJlIHdpdGggYSBodW1hbiBoYWlyOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSAiNjAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInBtMi41X3NjYWxlX2dyYXBoaWMtY29sb3JfMi5qcGciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly93d3cuZXBhLmdvdi9wbS1wb2xsdXRpb24vcGFydGljdWxhdGUtbWF0dGVyLXBtLWJhc2ljcylde3RhcmdldD0iX2JsYW5rIn0KCjwhLS0gPHAgYWxpZ249ImNlbnRlciI+IC0tPgo8IS0tICAgPGltZyB3aWR0aD0iNTAwIiBzcmM9Imh0dHBzOi8vd3d3LnNlbnNpcmlvbi5jb20vaW1hZ2VzL3NlbnNpcmlvbi1zcGVjaWFsaXN0LWFydGljbGUtZmlndXJlLTEtY2RkNzAuanBnIj4gLS0+CjwhLS0gPC9wPiAtLT4KCgo8dT5UaGUgZm9sbG93aW5nIHBsb3QgYW5kIHRhYmxlIHNob3cgdGhlIHJlbGF0aXZlIHNpemVzIG9mIHRoZXNlIGRpZmZlcmVudCBwb2xsdXRhbnRzIGluIG1pY3JvbWV0ZXJzKMK1bSk6PC91PgoKPHAgYWxpZ249ImNlbnRlciI+CiAgPGltZyB3aWR0aD0iNjAwIiBzcmM9Imh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvdGh1bWIvZC9kZi9BaXJib3JuZS1wYXJ0aWN1bGF0ZS1zaXplLWNoYXJ0LnN2Zy84MDBweC1BaXJib3JuZS1wYXJ0aWN1bGF0ZS1zaXplLWNoYXJ0LnN2Zy5wbmciPgo8L3A+CgojIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUGFydGljdWxhdGVzKV17dGFyZ2V0PSJfYmxhbmsifQoKCjxwIGFsaWduPSJjZW50ZXIiPgogIDxpbWcgd2lkdGg9IjUwMCIgc3JjPSJodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvZmlsZXMvQXJ0aWNsZXMvNTA1NTcwL2ZwdWJoLTA4LTAwMDE0LUhUTUwvaW1hZ2VfbS9mcHViaC0wOC0wMDAxNC10MDAyLmpwZyI+CjwvcD4KCiMjIyMjIFtbc291cmNlXShodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvYXJ0aWNsZXMvMTAuMzM4OS9mcHViaC4yMDIwLjAwMDE0L2Z1bGwpXXt0YXJnZXQ9Il9ibGFuayJ9CgoKPHU+VGhpcyB0YWJsZSBzaG93cyBob3cgZGVlcGx5IHNvbWUgb2YgdGhlIHNtYWxsZXIgZmluZSBwYXJ0aWNsZXMgY2FuIHBlbmV0cmF0ZSB3aXRoaW4gdGhlIGh1bWFuIGJvZHk6PC91PgoKPHAgYWxpZ249ImNlbnRlciI+CiAgPGltZyB3aWR0aD0iNTAwIiBzcmM9Imh0dHBzOi8vd3d3LmZyb250aWVyc2luLm9yZy9maWxlcy9BcnRpY2xlcy81MDU1NzAvZnB1YmgtMDgtMDAwMTQtSFRNTC9pbWFnZV9tL2ZwdWJoLTA4LTAwMDE0LXQwMDEuanBnIj4KPC9wPgoKIyMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vd3d3LmZyb250aWVyc2luLm9yZy9hcnRpY2xlcy8xMC4zMzg5L2ZwdWJoLjIwMjAuMDAwMTQvZnVsbClde3RhcmdldD0iX2JsYW5rIn0KCgojIyMjIE5lZ2F0aXZlIEltcGFjdCBvZiBQYXJ0aWN1bGF0ZSBFeHBvc3VyZSBvbiBIZWFsdGggCgpFeHBvc3VyZSB0byBhaXIgcG9sbHV0aW9uIGlzIGFzc29jaWF0ZWQgd2l0aCBoaWdoZXIgcmF0ZXMgb2YgW21vcnRhbGl0eV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNTc4MzE4Ni8pe3RhcmdldD0iX2JsYW5rIn0gaW4gb2xkZXIgYWR1bHRzIGFuZCBpcyBrbm93biB0byBiZSBhIHJpc2sgZmFjdG9yIGZvciBtYW55IGRpc2Vhc2VzIGFuZCBjb25kaXRpb25zIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG86CgoxKSBbQXN0aG1hXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3B1Ym1lZC8yOTI0MzkzNyl7dGFyZ2V0PSJfYmxhbmsifSAtIGZpbmUgcGFydGljbGUgZXhwb3N1cmUgKCoqUE1+Mi41fioqKSB3YXMgZm91bmQgdG8gYmUgYXNzb2NpYXRlZCB3aXRoIGhpZ2hlciByYXRlcyBvZiBhc3RobWEgaW4gY2hpbGRyZW4KMikgW0luZmxhbW1hdGlvbiBpbiB0eXBlIDEgZGlhYmV0ZXNdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcHVibWVkLzMxNDE5NzY1KXt0YXJnZXQ9Il9ibGFuayJ9IC0gZmluZSBwYXJ0aWNsZSBleHBvc3VyZSAoKipQTX4yLjV+KiopIGZyb20gdHJhZmZpYy1yZWxhdGVkIGFpciBwb2xsdXRpb24gd2FzIGFzc29jaWF0ZWQgd2l0aCBpbmNyZWFzZWQgbWVhc3VyZXMgb2YgaW5mbGFtbWF0b3J5IG1hcmtlcnMgaW4geW91dGhzIHdpdGggdHlwZSAxIGRpYWJldGVzCjMpIFtMdW5nIGZ1bmN0aW9uIGFuZCBlbXBoeXNlbWFdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcHVibWVkLzMxNDA4MTM1KXt0YXJnZXQ9Il9ibGFuayJ9IC0gaGlnaGVyIGNvbmNlbnRyYXRpb25zIG9mIG96b25lIChPfjN+KSwgbml0cm9nZW4gb3hpZGVzIChOT354fiksIGJsYWNrIGNhcmJvbiwgYW5kIGZpbmUgcGFydGljbGUgZXhwb3N1cmUgKipQTX4yLjV+KiogLCBhdCBzdHVkeSBiYXNlbGluZSB3ZXJlIHNpZ25pZmljYW50bHkgYXNzb2NpYXRlZCB3aXRoIGdyZWF0ZXIgaW5jcmVhc2VzIGluIHBlcmNlbnQgZW1waHlzZW1hIHBlciAxMCB5ZWFycyAKNCkgW0xvdyBiaXJ0aHdlaWdodF0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wdWJtZWQvMzEzODY2NDMpe3RhcmdldD0iX2JsYW5rIn0gLSBmaW5lIHBhcnRpY2xlIGV4cG9zdXJlKCoqUE1+Mi41fioqKSB3YXMgYXNzb2NpYXRlZCB3aXRoIGxvd2VyIGJpcnRoIHdlaWdodCBpbiBmdWxsLXRlcm0gbGl2ZSBiaXJ0aHMKNSkgW1ZpcmFsIEluZmVjdGlvbl0oaHR0cHM6Ly93d3cudGFuZGZvbmxpbmUuY29tL2RvaS9mdWxsLzEwLjEwODAvMDg5NTgzNzA3MDE2NjU0MzQpe3RhcmdldD0iX2JsYW5rIn0gLSBoaWdoZXIgcmF0ZXMgb2YgaW5mZWN0aW9uIGFuZCBpbmNyZWFzZWQgc2V2ZXJpdHkgb2YgaW5mZWN0aW9uIGFyZSBhc3NvY2lhdGVkIHdpdGggaGlnaGVyIGV4cG9zdXJlcyB0byBwb2xsdXRpb24gbGV2ZWxzIGluY2x1ZGluZyBmaW5lIHBhcnRpY2xlIGV4cG9zdXJlICgqKlBNfjIuNX4qKikKClNlZSB0aGlzIFtyZXZpZXcgYXJ0aWNsZV0oaHR0cHM6Ly93d3cuZnJvbnRpZXJzaW4ub3JnL2FydGljbGVzLzEwLjMzODkvZnB1YmguMjAyMC4wMDAxNC9mdWxsKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHNvdXJjZXMgb2YgYWlyIHBvbGx1dGlvbiBhbmQgdGhlIGluZmx1ZW5jZSBvZiBhaXIgcG9sbHV0aW9uIG9uIGhlYWx0aC4KCiMjIyMgU3BhcnNlIE1vbml0b3JpbmcgaXMgUHJvYmxlbWF0aWMgZm9yIFB1YmxpYyBIZWFsdGgKCkhpc3RvcmljYWxseSBlcGlkZW1pb2xvZ2ljYWwgc3R1ZGllcyB3b3VsZCBhc3Nlc3MgdGhlIGluZmx1ZW5jZSBvZiBhaXIgcG9sbHV0aW9uIG9uIGhlYWx0aCBvdXRjb21lcyBieSByZWx5aW5nIG9uIGEgbnVtYmVyIG9mIG1vbml0b3JzIGxvY2F0ZWQgYXJvdW5kIHRoZSBjb3VudHJ5LiBIb3dldmVyIGFzIGNhbiBiZSBzZWVuIGluIHRoZSBmb2xsb3dpbmcgZmlndXJlLCB0aGVzZSBtb25pdG9ycyByZW1haW4gdG8gYmUgcmVsYXRpdmVseSBzcGFyc2UgaW4gY2VydGFpbiByZWdpb25zIG9mIHRoZSBjb3VudHJ5LiBGdXJ0aGVybW9yZSwgZHJhbWF0aWMgZGlmZmVyZW5jZXMgaW4gcG9sbHV0aW9uIHJhdGVzIGNhbiBiZSBzZWVuIGV2ZW4gd2l0aGluIHRoZSBzYW1lIGNpdHkuCgo8cCBhbGlnbj0iY2VudGVyIj4KICA8aW1nIHdpZHRoPSI0MDAiIHNyYz0iaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNDEzNzI3Mi9iaW4vMTQ3Ni0wNjlYLTEzLTYzLTEuanBnIj4KPC9wPgoKIyMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vZWhqb3VybmFsLmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvMTQ3Ni0wNjlYLTEzLTYzKV17dGFyZ2V0PSJfYmxhbmsifQoKVGhpcyBsYWNrIG9mIGdyYW51bGFyaXR5IGluIGFpciBwb2xsdXRpb24gbW9uaXRvcmluZyBoYXMgaGluZGVyZWQgb3VyIGFiaWxpdHkgdG8gZGlzY2VybiB0aGUgZnVsbCBpbXBhY3Qgb2YgYWlyIHBvbGx1dGlvbiBvbiBoZWFsdGggYW5kIHRvIGlkZW50aWZ5IGF0LXJpc2sgbG9jYXRpb25zLiAKCgojIyMjIE1hY2hpbmUgTGVhcm5pbmcgT2ZmZXJzIGEgU29sdXRpb24KCkFuIFthcnRpY2xlXShodHRwczovL2Voam91cm5hbC5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2LzE0NzYtMDY5WC0xMy02Myl7dGFyZ2V0PSJfYmxhbmsifSBwdWJsaXNoZWQgaW4gdGhlICpFbnZpcm9ubWVudGFsIEhlYWx0aCogam91cm5hbCBkZWFsdCB3aXRoIHRoaXMgaXNzdWUgYnkgdXNpbmcgZGF0YSBhYm91dCBwb3B1bGF0aW9uIGRlbnNpdHksIHJvYWQgZGVuc2l0eSwgYW1vbmcgb3RoZXIgZmVhdHVyZXMgdG8gbW9kZWwgb3IgcHJlZGljdCBhaXIgcG9sbHV0aW9uIGxldmVscyBhdCBhIG1vcmUgbG9jYWxpemVkIHNjYWxlIHVzaW5nIG1hY2hpbmUgbGVhcm5pbmcgbWV0aG9kcy4gCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAidGhlcGFwZXIucG5nIikpCmBgYAoKIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30KWWFub3NreSwgSi4gRC4gZXQgYWwuIFNwYXRpby10ZW1wb3JhbCBtb2RlbGluZyBvZiBwYXJ0aWN1bGF0ZSBhaXIgcG9sbHV0aW9uIGluIHRoZSBjb250ZXJtaW5vdXMgVW5pdGVkIFN0YXRlcyB1c2luZyBnZW9ncmFwaGljIGFuZCBtZXRlb3JvbG9naWNhbCBwcmVkaWN0b3JzLiAqRW52aXJvbiBIZWFsdGgqIDEzLCA2MyAoMjAxNCkuCgojIyMjCgpUaGUgYXV0aG9ycyBvZiB0aGlzIGFydGljbGUgc3RhdGUgdGhhdDoKCj4gIkV4cG9zdXJlIHRvIGF0bW9zcGhlcmljIHBhcnRpY3VsYXRlIG1hdHRlciAoUE0pIHJlbWFpbnMgYW4gaW1wb3J0YW50IHB1YmxpYyBoZWFsdGggY29uY2VybiwKYWx0aG91Z2ggaXQgcmVtYWlucyBkaWZmaWN1bHQgdG8gcXVhbnRpZnkgYWNjdXJhdGVseSBhY3Jvc3MgbGFyZ2UgZ2VvZ3JhcGhpYyBhcmVhcyB3aXRoIHN1ZmZpY2llbnRseSBoaWdoIHNwYXRpYWwKcmVzb2x1dGlvbi4gUmVjZW50IGVwaWRlbWlvbG9naWMgYW5hbHlzZXMgaGF2ZSBkZW1vbnN0cmF0ZWQgdGhlIGltcG9ydGFuY2Ugb2Ygc3BhdGlhbGx5LSBhbmQgdGVtcG9yYWxseS1yZXNvbHZlZApleHBvc3VyZSBlc3RpbWF0ZXMsIHdoaWNoIHNob3cgbGFyZ2VyIFBNLW1lZGlhdGVkIGhlYWx0aCBlZmZlY3RzIGFzIGNvbXBhcmVkIHRvIG5lYXJlc3QgbW9uaXRvciBvcgpjb3VudHktc3BlY2lmaWMgYW1iaWVudCBjb25jZW50cmF0aW9ucy4iIAoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0gIjcwMCBweCIsIGV2YWwgPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgImRlYXRocy5wbmciKSkKYGBgCgpUaGUgYXJ0aWNsZSBhYm92ZSBleHBsYWlucyB0aGF0IG1hY2hpbmUgbGVhcm5pbmcgbWV0aG9kcyBjYW4gYmUgdXNlZCB0byBwcmVkaWN0IGFpciBwb2xsdXRpb24gbGV2ZWxzIHdoZW4gdHJhZGl0aW9uYWwgbW9uaXRvcmluZyBzeXN0ZW1zIGFyZSBub3QgYXZhaWxhYmxlIGluIGEgcGFydGljdWxhciBhcmVhIG9yIHdoZW4gdGhlcmUgaXMgbm90IGVub3VnaCBzcGF0aWFsIGdyYW51bGFyaXR5IHdpdGggY3VycmVudCBtb25pdG9yaW5nIHN5c3RlbXMuIFdlIHdpbGwgdXNlIHNpbWlsYXIgbWV0aG9kcyB0byBwcmVkaWN0IGFubnVhbCBhaXIgcG9sbHV0aW9uIGxldmVscyBzcGF0aWFsbHkgd2l0aGluIHRoZSBVUy4KCgojIyMgTWFpbiBRdWVzdGlvbnMKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb246IDwvdT48L2I+CgoxKSBDYW4gd2UgcHJlZGljdCBhbm51YWwgYXZlcmFnZSBhaXIgcG9sbHV0aW9uIGNvbmNlbnRyYXRpb25zIGF0IHRoZSBncmFudWxhcml0eSBvZiB6aXAgY29kZSByZWdpb25hbCBsZXZlbHMgdXNpbmcgcHJlZGljdG9ycyBzdWNoIGFzIGRhdGEgYWJvdXQgcG9wdWxhdGlvbiBkZW5zaXR5LCB1cmJhbml6YXRpb24sIHJvYWQgZGVuc2l0eSwgYXMgd2VsbCBhcywgc2F0ZWxsaXRlIHBvbGx1dGlvbiBkYXRhIGFuZCBjaGVtaWNhbCBtb2RlbGluZyBkYXRhPwoKIyMjIwoKIyMjIExlYXJuaW5nIE9iamVjdGl2ZXMgCgpJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHdpbGwgd2FsayB5b3UgdGhyb3VnaCBpbXBvcnRpbmcgZGF0YSBmcm9tIENTViBmaWxlcyBhbmQgcGVyZm9ybWluZyBtYWNoaW5lIGxlYXJuaW5nIG1ldGhvZHMgdG8gcHJlZGljdCBvdXIgb3V0Y29tZSB2YXJpYWJsZSBvZiBpbnRlcmVzdCAoaW4gdGhpcyBjYXNlIGFubnVhbCBmaW5lIHBhcnRpY2xlIGFpciBwb2xsdXRpb24gZXN0aW1hdGVzKS4gV2Ugd2lsbCBlc3BlY2lhbGx5IGZvY3VzIG9uIHVzaW5nIHBhY2thZ2VzIGFuZCBmdW5jdGlvbnMgZnJvbSB0aGUgW2BUaWR5dmVyc2VgXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSwgYW5kIG1vcmUgc3BlY2lmaWNhbGx5IHRoZSBbYHRpZHltb2RlbHNgXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdGlkeW1vZGVscy90aWR5bW9kZWxzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBwYWNrYWdlL2Vjb3N5c3RlbSBwcmltYXJpbHkgZGV2ZWxvcGVkIGFuZCBtYWludGFpbmVkIGJ5IFtNYXggS3Vobl0oaHR0cHM6Ly9yZXNvdXJjZXMucnN0dWRpby5jb20vYXV0aG9ycy9tYXgta3Vobil7dGFyZ2V0PSJfYmxhbmsifSBhbmQgW0RhdmlzIFZhdWdoYW5dKGh0dHBzOi8vcmVzb3VyY2VzLnJzdHVkaW8uY29tL2F1dGhvcnMvZGF2aXMtdmF1Z2hhbil7dGFyZ2V0PSJfYmxhbmsifS4gVGhpcyBwYWNrYWdlIGxvYWRzIG1vcmUgbW9kZWxpbmcgcmVsYXRlZCBwYWNrYWdlcyBsaWtlIGByc2FtcGxlYCwgYHJlY2lwZXNgLCBgcGFyc25pcGAsIGB5YXJkc3RpY2tgLCAgYW5kIGBkaWFsc2AuIFdlIHdpbGwgYWxzbyBicmllZmx5IGNvdmVyIHRoZSBgd29ya2Zsb3dzYCBhbmQgYHR1bmVgIHBhY2thZ2VzLiBUaGUgdGlkeXZlcnNlIGlzIGEgbGlicmFyeSBvZiBwYWNrYWdlcyBjcmVhdGVkIGJ5IFJTdHVkaW8uIFdoaWxlIHNvbWUgc3R1ZGVudHMgbWF5IGJlIGZhbWlsaWFyIHdpdGggcHJldmlvdXMgUiBwcm9ncmFtbWluZyBwYWNrYWdlcywgdGhlc2UgcGFja2FnZXMgbWFrZSBkYXRhIHNjaWVuY2UgaW4gUiBlc3BlY2lhbGx5IGVmZmljaWVudC4KCgpgYGB7ciwgb3V0LndpZHRoID0gIjIwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpCmBgYAoKYGBge3IsIG91dC53aWR0aCA9ICIxMDBweCIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly9wYnMudHdpbWcuY29tL21lZGlhL0RrQkZwU3NXNEFJeXlJTi5wbmciKQpgYGAKCgpXZSB3aWxsIGJlZ2luIGJ5IGxvYWRpbmcgdGhlIHBhY2thZ2VzIHRoYXQgd2Ugd2lsbCBuZWVkOgoKYGBge3J9CmxpYnJhcnkoaGVyZSkKbGlicmFyeShyZWFkcikKbGlicmFyeShkcGx5cikKbGlicmFyeShza2ltcikKbGlicmFyeShzdW1tYXJ5dG9vbHMpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGdnY29ycnBsb3QpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KHRpZHltb2RlbHMpIyBicm9vbSwgZGlhbHMsIGluZmVyLCBwYXJzbmlwLCBwdXJyciwgcmVjaXBlcywgcnNhbXBsZSwgdGliYmxlLCB5YXJkc3RpY2sKbGlicmFyeSh3b3JrZmxvd3MpCmxpYnJhcnkodmlwKQpsaWJyYXJ5KHR1bmUpCmxpYnJhcnkocmFuZG9tRm9yZXN0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeSh0aWR5cikKbGlicmFyeShsd2dlb20pICMgYWxsb3dzIDEyNjMKbGlicmFyeShzZikKbGlicmFyeShtYXBzKQpsaWJyYXJ5KHJuYXR1cmFsZWFydGgpCmxpYnJhcnkocmdlb3MpCmxpYnJhcnkoY293cGxvdCkKYGBgCgoKIFBhY2thZ2UgICB8IFVzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YQpbcmVhZHJdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGltcG9ydCB0aGUgQ1NWIGZpbGUgZGF0YQpbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHZpZXcvYXJyYW5nZS9maWx0ZXIvc2VsZWN0L2NvbXBhcmUgc3BlY2lmaWMgc3Vic2V0cyBvZiB0aGUgZGF0YSAKW3NraW1yXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc2tpbXIvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gZ2V0IGFuIG92ZXJ2aWV3IG9mIGRhdGEKW3N1bW1hcnl0b29sc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3NraW1yL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIGdldCBhbiBvdmVydmlldyBvZiBkYXRhIGluIGEgZGlmZmVyZW50IHN0eWxlClttYWdyaXR0cl0oaHR0cHM6Ly9tYWdyaXR0ci50aWR5dmVyc2Uub3JnL2FydGljbGVzL21hZ3JpdHRyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICB8IHRvIHVzZSB0aGUgYCU8PiVgIHBpcHBpbmcgb3BlcmF0b3IgCltjb3JycGxvdF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2NvcnJwbG90L3ZpZ25ldHRlcy9jb3JycGxvdC1pbnRyby5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gbWFrZSBsYXJnZSBjb3JyZWxhdGlvbiBwbG90cwpbZ2djb3JycGxvdF0oaHR0cDovL3d3dy5zdGhkYS5jb20vZW5nbGlzaC93aWtpL2dnY29ycnBsb3QtdmlzdWFsaXphdGlvbi1vZi1hLWNvcnJlbGF0aW9uLW1hdHJpeC11c2luZy1nZ3Bsb3QyKXwgYWxzbyB0byBtYWtlIGxhcmdlIGNvcnJlbGF0aW9uIHBsb3RzCltHR2FsbHldKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9HR2FsbHkvR0dhbGx5LnBkZil7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIG1ha2Ugc21hbGxlciBjb3JyZWxhdGlvbiBwbG90cyAgCltyc2FtcGxlXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3JzYW1wbGUvYXJ0aWNsZXMvQmFzaWNzLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICB8IHRvIHNwbGl0IHRoZSBkYXRhIGludG8gdGVzdGluZyBhbmQgdHJhaW5pbmcgc2V0cyBhbmQgdG8gc3BsaXQgdGhlIHRyYWluaW5nIHNldCBmb3IgY3Jvc3MtdmFsaWRhdGlvbiAgCltyZWNpcGVzXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3JlY2lwZXMvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byBwcmUtcHJvY2VzcyBkYXRhIGZvciBtb2RlbGluZyBpbiBhIHRpZHkgYW5kIHJlcHJvZHVjaWJsZSB3YXkgYW5kIHRvIGV4dHJhY3QgcHJlLXByb2Nlc3NlZCBkYXRhIChtYWpvciBmdW5jdGlvbnMgYXJlIGByZWNpcGUoKWAgLCBgcHJlcCgpYCBhbmQgdmFyaW91cyB0cmFuc2Zvcm1hdGlvbiBgc3RlcF8qKClgIGZ1bmN0aW9ucywgYXMgd2VsbCBhcyBganVpY2UoKWAgLSBleHRyYWN0cyBmaW5hbCBwcmVwcm9jZXNzZWQgdHJhaW5pbmcgZGF0YSBhbmQgYGJha2UoKWAgLSBhcHBsaWVzIHJlY2lwZSBzdGVwcyB0byB0ZXN0aW5nIGRhdGEpLiBTZWUgW2hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yZWNpcGVzL3JlY2lwZXMucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICBmb3IgbW9yZSBpbmZvLgpbcGFyc25pcF0oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby9wYXJzbmlwLyl7dGFyZ2V0PSJfYmxhbmsifSAgIHwgYW4gaW50ZXJmYWNlIHRvIGNyZWF0ZSBtb2RlbHMgKG1ham9yIGZ1bmN0aW9ucyBhcmUgIGBmaXQoKWAsIGBzZXRfZW5naW5lKClgKQpbeWFyZHN0aWNrXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3lhcmRzdGljay8pe3RhcmdldD0iX2JsYW5rIn0gICB8IHRvIGV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBtb2RlbHMKW2Jyb29tXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnL2Jsb2cvMjAxOC8wNy9icm9vbS0wLTUtMC8pe3RhcmdldD0iX2JsYW5rIn0gfCB0byBnZXQgdGlkeSBvdXRwdXQgZm9yIG91ciBtb2RlbCBmaXQgYW5kIHBlcmZvcm1hbmNlCltnZ3Bsb3QyXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYWtlIHZpc3VhbGl6YXRpb25zIHdpdGggbXVsdGlwbGUgbGF5ZXJzCltkaWFsc10oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy9ibG9nLzIwMTkvMTAvZGlhbHMtMC0wLTMvKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gc3BlY2lmeSBoeXBlci1wYXJhbWV0ZXIgdHVuaW5nClt0dW5lXShodHRwczovL3R1bmUudGlkeW1vZGVscy5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gcGVyZm9ybSBjcm9zcyB2YWxpZGF0aW9uLCB0dW5lIGh5cGVyLXBhcmFtZXRlcnMsIGFuZCBnZXQgcGVyZm9ybWFuY2UgbWV0cmljcwpbd29ya2Zsb3dzXShodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvd29ya2Zsb3dzL3ZlcnNpb25zLzAuMS4xKXt0YXJnZXQ9Il9ibGFuayJ9fCB0byBjcmVhdGUgbW9kZWxpbmcgd29ya2Zsb3cgdG8gc3RyZWFtbGluZSB0aGUgbW9kZWxpbmcgcHJvY2VzcwpbdmlwXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdmlwL3ZpcC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBjcmVhdGUgdmFyaWFibGUgaW1wb3J0YW5jZSBwbG90cwpbcmFuZG9tRm9yZXN0XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcmFuZG9tRm9yZXN0L3JhbmRvbUZvcmVzdC5wZGYpfCB0byBwZXJmb3JtIHRoZSByYW5kb20gZm9yZXN0IGFuYWx5c2lzCltzdHJpbmdyXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9zdHJpbmdyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYW5pcHVsYXRlIHRoZSB0ZXh0IHRoZSBtYXAgZGF0YQpbdGlkeXJdKGh0dHBzOi8vdGlkeXIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgICB8IHRvIHNlcGFyYXRlIGRhdGEgd2l0aGluIGEgY29sdW1uIGludG8gbXVsdGlwbGUgY29sdW1ucwpbcm5hdHVyYWxlYXJ0aF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3JuYXR1cmFsZWFydGgvUkVBRE1FLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBnZXQgdGhlIGdlb21ldHJ5IGRhdGEgZm9yIHRoZSBlYXJ0aCB0byBwbG90IHRoZSBVUwpbbWFwc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hcHMvbWFwcy5wZGYpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBnZXQgbWFwIGRhdGFiYXNlIGRhdGEgYWJvdXQgY291bnRpZXMgdG8gZHJhdyB0aGVtIG9uIG91ciBVUyBtYXAKW3NmXShodHRwczovL3Itc3BhdGlhbC5naXRodWIuaW8vc2YvKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gY29udmVydCB0aGUgbWFwIGRhdGEgaW50byBhIGRhdGEgZnJhbWUKW2x3Z2VvbV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2x3Z2VvbS9sd2dlb20ucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gdXNlIHRoZSBgc2ZgIGZ1bmN0aW9uIHRvIGNvbnZlcnQgdGhlIG1hcCBnZW9ncmFwaGljYWwgZGF0YQpbcmdlb3NdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yZ2Vvcy9yZ2Vvcy5wZGYpe3RhcmdldD0iX2JsYW5rIn0gfCB0byB1c2UgZ2VvbWV0cnkgZGF0YQpbY293cGxvdF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2Nvd3Bsb3QvdmlnbmV0dGVzL2ludHJvZHVjdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gYWxsb3cgcGxvdHMgdG8gYmUgY29tYmluZWQKX19fCgoKClRoZSBmaXJzdCB0aW1lIHdlIHVzZSBhIGZ1bmN0aW9uLCB3ZSB3aWxsIHVzZSB0aGUgYDo6YCB0byBpbmRpY2F0ZSB3aGljaCBwYWNrYWdlIHdlIGFyZSB1c2luZy4gVW5sZXNzIHdlIGhhdmUgb3ZlcmxhcHBpbmcgZnVuY3Rpb24gbmFtZXMsIHRoaXMgaXMgbm90IG5lY2Vzc2FyeSwgYnV0IHdlIHdpbGwgaW5jbHVkZSBpdCBoZXJlIHRvIGJlIGluZm9ybWF0aXZlIGFib3V0IHdoZXJlIHRoZSBmdW5jdGlvbnMgd2Ugd2lsbCB1c2UgY29tZSBmcm9tLgoKCiMjIyBDb250ZXh0CgpUaGUgW1N0YXRlIG9mIEdsb2JhbCBBaXJdKGh0dHBzOi8vd3d3LnN0YXRlb2ZnbG9iYWxhaXIub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSBpcyBhIHJlcG9ydCByZWxlYXNlZCBldmVyeSB5ZWFyIHRvIGNvbW11bmljYXRlIHRoZSBpbXBhY3Qgb2YgYWlyIHBvbGx1dGlvbiBvbiBwdWJsaWMgaGVhbHRoLiAKClRoZSBbU3RhdGUgb2YgR2xvYmFsIEFpciAyMDE5IHJlcG9ydF0oaHR0cHM6Ly93d3cuc3RhdGVvZmdsb2JhbGFpci5vcmcvc2l0ZXMvZGVmYXVsdC9maWxlcy9zb2dhXzIwMTlfcmVwb3J0LnBkZil7dGFyZ2V0PSJfYmxhbmsifQp3aGljaCB1c2VzIGRhdGEgZnJvbSAyMDE3IHN0YXRlZCB0aGF0OgoKPiBBaXIgcG9sbHV0aW9uIGlzIHRoZSAqKmZpZnRoKiogbGVhZGluZyByaXNrIGZhY3RvciBmb3IgbW9ydGFsaXR5IHdvcmxkd2lkZS4gSXQgaXMgcmVzcG9uc2libGUgZm9yIG1vcmUKZGVhdGhzIHRoYW4gbWFueSBiZXR0ZXIta25vd24gcmlzayBmYWN0b3JzIHN1Y2ggYXMgbWFsbnV0cml0aW9uLCBhbGNvaG9sIHVzZSwgYW5kIHBoeXNpY2FsIGluYWN0aXZpdHkuCkVhY2ggeWVhciwgKiptb3JlKiogcGVvcGxlIGRpZSBmcm9tIGFpciBwb2xsdXRpb27igJNyZWxhdGVkIGRpc2Vhc2UgdGhhbiBmcm9tIHJvYWQgKip0cmFmZmljIGluanVyaWVzKiogb3IgKiptYWxhcmlhKiouCgo8cCBhbGlnbj0iY2VudGVyIj4KICA8aW1nIHdpZHRoPSI2MDAiIHNyYz0iaHR0cHM6Ly93d3cuaGVhbHRoZWZmZWN0cy5vcmcvc2l0ZXMvZGVmYXVsdC9maWxlcy9Tb0dBLUZpZ3VyZXMtMDEuanBnIj4KPC9wPgoKVGhlIHJlcG9ydCBhbHNvIHN0YXRlZCB0aGF0OgoKPkluIDIwMTcsIGFpciBwb2xsdXRpb24gaXMgZXN0aW1hdGVkIHRvIGhhdmUgY29udHJpYnV0ZWQgdG8gY2xvc2UgdG8gNSBtaWxsaW9uCmRlYXRocyBnbG9iYWxseSDigJQgbmVhcmx5ICoqMSBpbiBldmVyeSAxMCBkZWF0aHMqKi4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCIyMDE3ZGVhdGhzLnBuZyIpKQpgYGAKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5zdGF0ZW9mZ2xvYmFsYWlyLm9yZy9zaXRlcy9kZWZhdWx0L2ZpbGVzL3NvZ2FfMjAxOV9mYWN0X3NoZWV0LnBkZil7dGFyZ2V0PSJfYmxhbmsifQoKVGhlIFtTdGF0ZSBvZiBHbG9iYWwgQWlyIDIwMTggcmVwb3J0XShodHRwczovL3d3dy5zdGF0ZW9mZ2xvYmFsYWlyLm9yZy9zaXRlcy9kZWZhdWx0L2ZpbGVzL3NvZ2EtMjAxOC1yZXBvcnQucGRmKXt0YXJnZXQ9Il9ibGFuayJ9ICB1c2luZyBkYXRhIGZyb20gMjAxNiB3aGljaCBzZXBhcmF0ZWQgZGlmZmVyZW50IHR5cGVzIG9mIGFpciBwb2xsdXRpb24sIGZvdW5kIHRoYXQgKipwYXJ0aWN1bGF0ZSBwb2xsdXRpb24gd2FzIHBhcnRpY3VsYXJseSBhc3NvY2lhdGVkIHdpdGggbW9ydGFsaXR5KiouCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwiMjAxN21vcnRhbGl0eS5wbmciKSkKYGBgCgpUaGUgMjAxOSByZXBvcnQgc2hvd3MgdGhhdCB0aGUgaGlnaGVzdCBsZXZlbHMgb2YgZmluZSBwYXJ0aWN1bGF0ZSBwb2xsdXRpb24gb2NjdXJzIGluIEFmcmljYSBhbmQgQXNpYSBhbmQgdGhhdDoKCj4gTW9yZSB0aGFuICoqOTAlKiogb2YgcGVvcGxlIHdvcmxkd2lkZSBsaXZlIGluIGFyZWFzICoqZXhjZWVkaW5nKiogdGhlIFdvcmxkIEhlYWx0aCBPcmdhbml6YXRpb24gKFdITykgKipHdWlkZWxpbmUqKiBmb3IgaGVhbHRoeSBhaXIuIE1vcmUgdGhhbiBoYWxmIGxpdmUgaW4gYXJlYXMgdGhhdCBkbyBub3QgZXZlbiBtZWV0IFdIT+KAmXMgbGVhc3Qtc3RyaW5nZW50IGFpciBxdWFsaXR5IHRhcmdldC4KCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJQTXdvcmxkLnBuZyIpKQpgYGAKCkxvb2tpbmcgYXQgdGhlIFVTIHNwZWNpZmljYWxseSwgYWlyIHBvbGx1dGlvbiBsZXZlbHMgYXJlIGdlbmVyYWxseSBpbXByb3ZpbmcuIFRoZSBVUyBFbnZpcm9ubWVudGFsIFByb3RlY3Rpb24gQWdlbmN5IChFUEEpIGFsc28gcmVsZWFzZXMgYSByZXBvcnQgYWJvdXQgYWlyIHBvbGx1dGlvbiBsZXZlbHMgY2FsbGVkIFsqT3VyIE5hdGlvbidzIEFpcipdKGh0dHBzOi8vZ2lzcHViLmVwYS5nb3YvYWlyL3RyZW5kc3JlcG9ydC8yMDE5LyNob21lKXt0YXJnZXQ9Il9ibGFuayJ9LgoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIlVTLnBuZyIpKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly9naXNwdWIuZXBhLmdvdi9haXIvdHJlbmRzcmVwb3J0LzIwMTkvZG9jdW1lbnRhdGlvbi9BaXJUcmVuZHNfRmx5ZXIucGRmKXt0YXJnZXQ9Il9ibGFuayJ9CgpIb3dldmVyLCBhaXIgcG9sbHV0aW9uICoqY29udGludWVzIHRvIGNvbnRyaWJ1dGUgdG8gaGVhbHRoIHJpc2sgZm9yIEFtZXJpY2FucyoqLCBpbiBwYXJ0aWN1bGFyIGluICoqcmVnaW9ucyB3aXRoIGhpZ2hlciB0aGFuIG5hdGlvbmFsIGF2ZXJhZ2UgcmF0ZXMqKiBvZiBwb2xsdXRpb24gdGhhdCBhY3R1YWxseSBhdCB0aW1lIGV4Y2VlZCB0aGUgd29ybGQgaGVhbHRoIG9yZ2FuaXphdGlvbidzIHJlY29tbWVuZGVkIGxldmVsLiBUaHVzIGl0IGlzIG5lY2Vzc2FyeSB0byBvYnRhaW4gaGlnaCBzcGF0aWFsIGdyYW51bGFyaXR5IGluIGVzdGltYXRlcyBvZiBhaXIgcG9sbHV0aW9uIGluIG9yZGVyIHRvIGlkZW50aWZ5IGxvY2F0aW9ucyB3aGVyZSBwb3B1bGF0aW9ucyBhcmUgZXhwZXJpZW5jaW5nIGhhcm1mdWwgbGV2ZWxzIG9mIGV4cG9zdXJlLgoKCllvdSBjYW4gc2VlIHRoYXQgY3VycmVudCBhaXIgcXVhbGl0eSBjb25kaXRpb25zIGF0IHRoaXMgW3dlYnNpdGVdKGh0dHBzOi8vYXFpY24ub3JnL2NpdHkvdXNhLyl7dGFyZ2V0PSJfYmxhbmsifSBhbmQgeW91IHdpbGwgbm90aWNlIHZhcmlhdGlvbiBhY3Jvc3MgZGlmZmVyZW50IGNpdGllcy4KCkhlcmUgd2VyZSB0aGUgY29uZGl0aW9ucyBpbiBUb3Bla2EgS2Fuc2FzIHdoZW4gdGhpcyB3YXMgd3JpdHRlbjoKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJLYW5zYXMucG5nIikpCmBgYAoKSXQgcmVwb3J0cyBwYXJ0aWN1bGF0ZSB2YWx1ZXMgdXNpbmcgd2hhdCBpcyBjYWxsZWQgdGhlIFtBaXIgUXVhbGl0eSBJbmRleF0oaHR0cHM6Ly93d3cuYWlybm93Lmdvdi9pbmRleC5jZm0/YWN0aW9uPWFxaWJhc2ljcy5hcWkpe3RhcmdldD0iX2JsYW5rIn0gc2NhbGUgKEFRSSksIHRoaXMgW2NhbGN1bGF0b3JdKGh0dHBzOi8vYWlybm93Lmdvdi9pbmRleC5jZm0/YWN0aW9uPWFpcm5vdy5jYWxjdWxhdG9yKXt0YXJnZXQ9Il9ibGFuayJ9IGluZGljYXRlcyB0aGF0IDExNCBBUUkgaXMgZXF1aXZhbGVudCB0byA0MC43IHVnL21eM14gYW5kIGlzIGNvbnNpZGVyZWQgdW5oZWFsdGh5IGZvciBzZW5zaXRpdmUgaW5kaXZpZHVhbHMuIFRodXMgc29tZSBhcmVhcyB2ZXJ5IG11Y2ggZXhjZWVkIHRoZSBXb3JsZCBIZWFsdGggT3JnYW5pemF0aW9uIChXSE8pICBhbm51YWwgZXhwb3N1cmUgZ3VpZGVsaW5lICgxMCB1Zy9tXjNeKSBhdCBjZXJ0YWluIHRpbWVzIGFuZCB0aGlzIG1heSBhZHZlcnNlbHkgYWZmZWN0IHRoZSBoZWFsdGggb2YgcGVvcGxlIGxpdmluZyBpbiB0aGVzZSBsb2NhdGlvbnMuCgpGdXJ0aGVybW9yZSwgYWR2ZXJzZSBoZWFsdGggZWZmZWN0cyBoYXZlIGJlZW4gYXNzb2NpYXRlZCB3aXRoIHBvcHVsYXRpb25zIGV4cGVyaWVuY2luZyBoaWdoZXIgcG9sbHV0aW9uIGV4cG9zdXJlIGRlc3BpdGUgdGhlIGxldmVscyBiZWluZyBiZWxvdyBzdWdnZXN0ZWQgZ3VpZGVsaW5lcy4gU2Vjb25kbHksIGl0IGFwcGVhcnMgdGhhdCB0aGUgY29tcG9zaXRpb24gb2YgdGhlIHBhcnRpY3VsYXRlIG1hdGVyIGFuZCB0aGUgaW5mbHVlbmNlIG9mIG90aGVyIGRlbW9ncmFwaGljIGZhY3RvcnMgbWF5IG1ha2Ugc3BlY2lmaWMgcG9wdWxhdGlvbnMgbW9yZSBhdCByaXNrIGZvciBhZHZlcnNlIGhlYWx0aCBlZmZlY3RzIGR1ZSB0byBhaXIgcG9sbHV0aW9uLiBTZWUgdGhpcyBbYXJ0aWNsZV0oaHR0cHM6Ly93d3cubmVqbS5vcmcvZG9pL2Z1bGwvMTAuMTA1Ni9ORUpNb2ExNzAyNzQ3KXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGRldGFpbHMuCgpUaGUgbW9uaXRvciBkYXRhIHRoYXQgd2Ugd2lsbCB1c2UgaW4gdGhpcyBjYXNlIHN0dWR5IGNvbWVzIGZyb20gYSBzeXN0ZW0gb2YgbW9uaXRvcnMgaW4gd2hpY2ggcm91Z2hseSA5MCUgYXJlIGxvY2F0ZWQgd2l0aGluIGNpdGllcy4gVGh1cyB0aGVyZSBpcyBhbiAqKmVxdWl0eSBpc3N1ZSoqIGluIHRlcm1zIG9mIGNhcHR1cmluZyB0aGUgYWlyIHBvbGx1dGlvbiBsZXZlbHMgb2YgbW9yZSBydXJhbCBhcmVhcy4gVGhlcmVmb3JlLCB0byBnZXQgYSBiZXR0ZXIgc2Vuc2Ugb2YgdGhlIHBvbGx1dGlvbiBleHBvc3VyZXMgZm9yIHRoZSBpbmRpdmlkdWFscyBsaXZpbmcgaW4gdGhlc2UgYXJlYXMsIG1ldGhvZHMgbGlrZSBtYWNoaW5lIGxlYXJuaW5nIGNhbiBiZSB2ZXJ5IHVzZWZ1bCB0byBlc3RpbWF0ZSBhaXIgcG9sbHV0aW9uIGxldmVscyBpbiAqKmFyZWFzIHdpdGggbGl0dGxlIHRvIG5vIG1vbml0b3JpbmcqKi4KCkluZGVlZCwgbWFjaGluZSBsZWFybmluZyBtZXRob2RzIGFyZSBpbiBmYWN0IHVzZWQgdG8gYmUgYWJsZSB0byBlc3RpbWF0ZSBhaXIgcG9sbHV0aW9uIGluIHRoZXNlIGxvdyBtb25pdG9yaW5nIGFyZWFzIHNvIHRoYXQgd2UgY2FuIG1ha2UgYSBtYXAgbGlrZSB0aGlzIHdoZXJlIHdlIGhhdmUgYW5udWFsIGVzdGltYXRlcyBmb3IgYWxsIG9mIHRoZSBjb250aWd1b3VzIFVTOgoKPHAgYWxpZ249ImNlbnRlciI+CiAgPGltZyB3aWR0aD0iNjAwIiBzcmM9Imh0dHBzOi8vYXJjLWFuZ2xlcmZpc2gtd2FzaHBvc3QtcHJvZC13YXNocG9zdC5zMy5hbWF6b25hd3MuY29tL3B1YmxpYy9TQVdPRUdCWE1WR1E3QVM1UFo2VVVPWDZGWS5wbmciPgo8L3A+CgoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5nb29nbGUuY29tL3VybD9zYT1pJnVybD1odHRwcyUzQSUyRiUyRnd3dy53YXNoaW5ndG9ucG9zdC5jb20lMkZidXNpbmVzcyUyRjIwMTklMkYxMCUyRjIzJTJGYWlyLXBvbGx1dGlvbi1pcy1nZXR0aW5nLXdvcnNlLWRhdGEtc2hvdy1tb3JlLXBlb3BsZS1hcmUtZHlpbmclMkYmcHNpZz1BT3ZWYXczdi1aRFRCUG5MUDJNWXRLZjNVbmRqJnVzdD0xNTg1Nzg0NDc5MDY4MDAwJnNvdXJjZT1pbWFnZXMmY2Q9dmZlJnZlZD0wQ0FJUWpSeHFGd29UQ1BDeW45Znh4ZWdDRlFBQUFBQWRBQUFBQUJBZCl7dGFyZ2V0PSJfYmxhbmsifQoKVGhpcyBpcyB3aGF0IHdlIGFpbSB0byBhY2hpZXZlIGluIHRoaXMgY2FzZSBzdHVkeS4KCiMjIyBMaW1pdGF0aW9ucwoKVGhlcmUgYXJlIHNvbWUgaW1wb3J0YW50IGNvbnNpZGVyYXRpb25zIHJlZ2FyZGluZyB0aGlzIGRhdGEgYW5hbHlzaXMgdG8ga2VlcCBpbiBtaW5kOiAKCjEpIFRoZSBkYXRhIGluIG91ciBhbmFseXNpcyBkb2VzIG5vdCBpbmNsdWRlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjb21wb3NpdGlvbiBvZiBwYXJ0aWN1bGF0ZSBtYXRlci4gRGlmZmVyZW50IHR5cGVzIG9mIHBhcnRpY3VsYXRlcyBtYXkgYmUgbW9yZSBiZW5pZ24gb3IgZGVsZXRlcmlvdXMgZm9yIGhlYWx0aCBvdXRjb21lcy4KCjIpIE91dGRvb3IgcG9sbHV0aW9uIGxldmVscyBhcmUgbm90IG5lY2Vzc2FyaWx5IGFuIGluZGljYXRpb24gb2Ygb2YgaW5kaXZpZHVhbCBleHBvc3VyZXMuIFBlb3BsZSBzcGVuZCBkaWZmZXJpbmcgYW1vdW50cyBvZiB0aW1lIGluZG9vcnMgYW5kIG91dGRvb3JzIGFuZCBhcmUgZXhwb3NlZCB0byBkaWZmZXJlbnQgcG9sbHV0aW9uIGxldmVscyBpbmRvb3JzLiBQZW9wbGUgYXJlIG5vdyBkZXZlbG9waW5nIHBlcnNvbmFsIG1vbml0b3Jpbmcgc3lzdGVtcyB0byB0cmFjayBhaXIgcG9sbHV0aW9uIGxldmVscyBvbiB0aGUgcGVyc29uYWwgbGV2ZWwuCgpPdXIgYW5hbHlzaXMgd2lsbCB1c2UgYW5udWFsIG1lYW4gZXN0aW1hdGVzLCBob3dldmVyIHBvbGx1dGlvbiBsZXZlbHMgY2FuIHZhcnkgZ3JlYXRseSBieSBzZWFzb24sIGRheSBhbmQgZXZlbiBob3VyLiBUaGVyZSBhcmUgZGF0YSBzb3VyY2VzIHRoYXQgaGF2ZSBmaW5lciBsZXZlbHMgb2YgdGVtcG9yYWwgZGF0YSwgaG93ZXZlciB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBsb25nIHRlcm0gZXhwb3N1cmVzLCBhcyB0aGVzZSBhcHBlYXIgdG8gYmUgdGhlIG1vc3QgaW5mbHVlbnRpYWwgZm9yIGhlYWx0aCBvdXRjb21lcywgc28gd2UgY2hvc2UgdG8gdXNlIGFubnVhbCBsZXZlbCBkYXRhLiAKCgojIyBXaGF0IGFyZSB0aGUgZGF0YT8KCkluIE1hY2hpbmUgTGVhcm5pbmcgZm9yIHByZWRpY3Rpb24sIHRoZXJlIGFyZSB0d28gbWFpbiB0eXBlcyBvZiB2YXJpYWJsZXM6CgoxKSBPdXRjb21lIHZhcmlhYmxlCjIpIFByZWRpY3RvciB2YXJpYWJsZXMKClRoZSAqKm91dGNvbWUgdmFyaWFibGUqKiBpcyB3aGF0IGFyZSB0cnlpbmcgdG8gKipwcmVkaWN0KiouIEluIGJ1aWxkaW5nIG91ciBtb2RlbCB3ZSBhY3R1YWxseSBoYXZlIHRoZSBvdXRjb21lIHZhcmlhYmxlIGRhdGEsIGJ1dCB3ZSB3YW50IHRvIHNlZSBob3cgd2VsbCBvdXIgcHJlZGljdG9yIHZhcmlhYmxlcyBjYW4gZXhwbGFpbiB0aGUgdmFyaWF0aW9uIGluIG91ciBvdXRjb21lIGRhdGEuIFRoaXMgZ2l2ZXMgdXMgYSBzZW5zZSBvZiBob3cgd2VsbCB3ZSBjYW4gdXNlIHRoZSBwcmVkaWN0b3IgdmFyaWFibGUgZGF0YSB0byBwcmVkaWN0IG91ciBvdXRjb21lIHZhcmlhYmxlIGxldmVscyB3aGVuIHdlIGluIGZhY3QgZG8gbm90IGhhdmUgZGF0YSBhYm91dCB0aGUgb3V0Y29tZS4KCkFzIGEgc2ltcGxlciBleGFtcGxlLCBpbWFnaW5lIHRoYXQgd2UgaGF2ZSBkYXRhIGFib3V0IHRoZSBzYWxlcyBhbmQgY2hhcmFjdGVyaXN0aWNzIG9mIGNhcnMgZnJvbSBsYXN0IHllYXIgYW5kIHdlIHdhbnQgdG8gcHJlZGljdCB3aGljaCBjYXJzIG1pZ2h0IHNlbGwgd2VsbCB0aGlzIHllYXIuIFdlIGRvIG5vdCBoYXZlIHRoZSBzYWxlcyBkYXRhIHlldCBmb3IgdGhpcyB5ZWFyLCBidXQgd2UgZG8ga25vdyB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIG91ciBjYXJzIGZvciB0aGlzIHllYXIuIFdlIGNhbiB1c2UgYSBtb2RlbCBvZiB0aGUgY2hhcmFjdGVyaXN0aWNzIHRoYXQgZXhwbGFpbmVkIHNhbGVzIGxhc3QgeWVhciB0byBlc3RpbWF0ZSB3aGF0IGNhcnMgbWlnaHQgc2VsbCB3ZWxsIHRoaXMgeWVhci4gSW4gdGhpcyBjYXNlLCBvdXIgb3V0Y29tZSB2YXJpYWJsZSBpcyB0aGUgc2FsZSBwZXJmb3JtYW5jZSBvZiB0aGUgY2Fycywgd2hpbGUgdGhlIGRpZmZlcmVudCBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIGNhcnMgbWFrZSB1cCBvdXIgcHJlZGljdG9yIG9yIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4KCkluIHRoaXMgY2FzZSBzdHVkeSwgd2Ugd2lsbCBldmFsdWF0ZSBhaXIgcG9sbHV0aW9uIG1vbml0b3IgZGF0YSBvZiBmaW5lIHBhcnRpY3VsYXRlIG1hdGVyIChQTX4yLjV+KSBpbiB0aGUgY29udGlndW91cyBVUyBmcm9tIDIwMDgsIGFzIHdlbGwgYXMgZGF0YSBhYm91dCBwb3B1bGF0aW9uIGRlbnNpdHksIHJvYWQgZGVuc2l0eSwgdXJiYW5pemF0aW9uIGxldmVscywgYW5kIE5BU0Egc2F0ZWxsaXRlIGRhdGEgdG8gZGV2ZWxvcCBtb2RlbHMgdG8gcHJlZGljdCBsb2NhbGl6ZWQgYWlyIHBvbGx1dGlvbiBsZXZlbHMuIAoKVGhlIG1vbml0b3IgZGF0YSB3aWxsIGJlIG91ciAqKm91dGNvbWUgdmFyaWFibGUqKi4gIFdlIHdhbnQgdG8gZGV0ZXJtaW5lIGlmIHdlIGNhbiAqKnByZWRpY3QqKiBhaXIgcG9sbHV0aW9uIGxldmVscyBiYXNlZCBvbiBvdGhlciB0eXBlcyBvZiBkYXRhLCBsaWtlIHJvYWQgZGVuc2l0eSBhbmQgcG9wdWxhdGlvbiBkZW5zaXR5IHRvIHNlZSBpZiB3ZSBjYW4gdXNlIHRoZXNlIGRhdGEgdG8gcHJlZGljdCBhaXIgcG9sbHV0aW9uIGluIGFyZWFzIHdoZXJlIHRoZXJlIGFyZSBubyBtb25pdG9ycy4gCgoKIyMjIE91ciBvdXRjb21lIHZhcmlhYmxlCgpUaGUgbW9uaXRvciBkYXRhIHRoYXQgd2Ugd2lsbCBiZSB1c2luZyBjb21lcyBmcm9tICoqW2dyYXZpbWV0cmljIG1vbml0b3JzXShodHRwczovL3B1YmxpY2xhYi5vcmcvd2lraS9maWx0ZXItcG0pe3RhcmdldD0iX2JsYW5rIn0qKiBvcGVyYXRlZCBieSB0aGUgVVMgW0VuaXZvcm5tZW50YWwgUHJvdGVjdGlvbiBBZ2VuY3kgKEVQQSldKGh0dHBzOi8vd3d3LmVwYS5nb3YvKXt0YXJnZXQ9Il9ibGFuayJ9LiBUaGVzZSBtb25pdG9ycyB1c2UgYSBmaWx0cmF0aW9uIHN5c3RlbSB0byBzcGVjaWZpY2FsbHkgY2FwdHVyZSBmaW5lIHBhcnRpY3VsYXRlIG1hdHRlci4gVGhlIHdlaWdodCBvZiB0aGlzIG1hdHRlciBpcyBtYW51YWxseSBtZWFzdXJlZCBkYWlseSBvciB3ZWVrbHkuIFNlZSBbaGVyZV0oaHR0cHM6Ly93d3czLmVwYS5nb3YvdHRuYW10aTEvZmlsZXMvYW1iaWVudC9wbTI1L3NwZWMvUlRJR3Jhdk1hc3NTT1BGSU5BTC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gZm9yIHRoZSBFUEEgc3RhbmRhcmQgb3BlcmF0aW5nIHByb2NlZHVyZSBmb3IgUE0gZ3JhdmltZXRyaWMgYW5hbHlzaXMgaW4gMjAwOC4KCgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoPSIxNTBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsImZpbHRlci5wbmciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly9wdWJsaWNsYWIub3JnL3dpa2kvZmlsdGVyLXBtKV17dGFyZ2V0PSJfYmxhbmsifQoKSGVyZSBpcyBhbiBpbWFnZSBvZiB3aGF0IHRoZSBncmF2aW1ldHJpYyBtb25pdG9ycyBsb29rIGxpa2U6CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjEwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwibW9uaXRvci5wbmciKSkKYGBgCgoKR3JhdmltZXRyaWMgYW5hbHlzaXMgaXMgYWxzbyB1c2VkIGZvciBbZW1pc3Npb24gdGVzdGluZ10oaHR0cHM6Ly93d3cubXQuY29tL3VzL2VuL2hvbWUvYXBwbGljYXRpb25zL0xhYm9yYXRvcnlfd2VpZ2hpbmcvZW1pc3Npb25zLXRlc3RpbmctcGFydGljdWxhdGUtbWF0dGVyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uIFRoZSBzYW1lIGlkZWEgYXBwbGllczogYSBmcmVzaCBmaWx0ZXIgaXMgYXBwbGllZCBhbmQgdGhlIGRlc2lyZWQgYW1vdW50IG9mIHRpbWUgcGFzc2VzLCB0aGVuIHRoZSBmaWx0ZXIgaXMgcmVtb3ZlZCBhbmQgd2VpZ2hlZC4gCgpUaGVyZSBhcmUgW290aGVyIG1vbml0b3Jpbmcgc3lzdGVtc10oaHR0cHM6Ly93d3cuc2Vuc2lyaW9uLmNvbS9lbi9hYm91dC11cy9uZXdzcm9vbS9zZW5zaXJpb24tc3BlY2lhbGlzdC1hcnRpY2xlcy9wYXJ0aWN1bGF0ZS1tYXR0ZXItc2Vuc2luZy1mb3ItYWlyLXF1YWxpdHktbWVhc3VyZW1lbnRzLyl7dGFyZ2V0PSJfYmxhbmsifSB0aGF0IGNhbiBwcm92aWRlIGhvdXJseSBtZWFzdXJlbWVudHMsIGJ1dCB3ZSB3aWxsIG5vdCBiZSB1c2luZyBkYXRhIGZyb20gdGhlc2UgbW9uaXRvcnMgaW4gb3VyIGFuYWx5c2lzLiBHcmF2aW1ldHJpYyBhbmFseXNpcyBpcyBjb25zaWRlcmVkIHRvIGJlIGFtb25nIHRoZSBtb3N0IGFjY3VyYXRlIG1ldGhvZHMuCgpJbiBvdXIgY3N2LCB0aGUgKip2YWx1ZSoqIGNvbHVtbiBpbmRpY2F0ZXMgdGhlIFBNfjIuNX4gbW9uaXRvciBhdmVyYWdlIGZvciAyMDA4IGluIG1hc3Mgb2YgZmluZSBwYXJ0aWNsZXMvdm9sdW1lIG9mIGFpciBmb3IgODc2IGdyYXZpbWV0cmljIG1vbml0b3JzLiBUaGUgdW5pdHMgYXJlIG1pY3JvIGdyYW1zIG9mIGZpbmUgcGFydGljdWxhdGUgbWF0ZXIgKFBNKSB0aGF0IGlzIGxlc3MgdGhhbiAyLjUgbWljcm9tZXRlcnMgaW4gZGlhbWV0ZXIgcGVyIGN1YmljIG1ldGVyIG9mIGFpciAtIG1hc3MgY29uY2VudHJhdGlvbiAodWcvbV4zXikuICBSZWNhbGwgdGhlIHRoZSBXSE8gZXhwb3N1cmUgIGd1aWRlbGluZSBpcyA8IDEwIHVnL21eM14gb24gYXZlcmFnZSBhbm51YWxseSBmb3IgUE1+Mi41fi4KCiMjIyBPdXIgcHJlZGljdG9yIHZhcmlhYmxlcwoKVGhlcmUgYXJlIDQ4IHByZWRpY3RvciB2YXJpYWJsZXMgd2l0aCB2YWx1ZXMgZm9yIGVhY2ggb2YgdGhlIDg3NiBtb25pdG9ycyBpbmNsdWRlZCBpbiBvdXIgb3V0Y29tZSB2YXJpYWJsZS4gVGhlIGRhdGEgY29tZXMgZnJvbSB0aGUgVVMgW0VuaXZvcm5tZW50YWwgUHJvdGVjdGlvbiBBZ2VuY3kgKEVQQSldKGh0dHBzOi8vd3d3LmVwYS5nb3YvKXt0YXJnZXQ9Il9ibGFuayJ9LCB0aGUgW05hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlzdHJhdGlvbiAoTkFTQSldKGh0dHBzOi8vd3d3Lm5hc2EuZ292Lyl7dGFyZ2V0PSJfYmxhbmsifSwgdGhlIFVTIFtDZW5zdXNdKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvYWJvdXQvd2hhdC9jZW5zdXMtYXQtYS1nbGFuY2UuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSwgYW5kIHRoZSBbTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljcyAoTkNIUyldKGh0dHBzOi8vd3d3LmNkYy5nb3YvbmNocy9hYm91dC9pbmRleC5odG0pe3RhcmdldD0iX2JsYW5rIn0uCgo8ZGV0YWlscz48c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgYSB0YWJsZSBhYm91dCB0aGUgdmFyaWFibGVzIDwvc3VtbWFyeT4KCgpWYXJpYWJsZSAgIHwgRGV0YWlscyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCioqaWQqKiAgfCBNb25pdG9yIG51bWJlciAgPGJyPiAtLSB0aGUgY291bnR5IG51bWJlciBpcyBpbmRpY2F0ZWQgYmVmb3JlIHRoZSBkZWNpbWFsIDxicj4gLS0gdGhlIG1vbml0b3IgbnVtYmVyIGlzIGluZGljYXRlZCBhZnRlciB0aGUgZGVjaW1hbCA8YnI+ICAqKkV4YW1wbGUqKjogMTA3My4wMDIzICBpcyBKZWZmZXJzb24gY291bnR5ICgxMDczKSBhbmQgLjAwMjMgb25lIG9mIDggbW9uaXRvcnMgCioqZmlwcyoqIHwgRmVkZXJhbCBpbmZvcm1hdGlvbiBwcm9jZXNzaW5nIHN0YW5kYXJkIG51bWJlciBmb3IgdGhlIGNvdW50eSB3aGVyZSB0aGUgbW9uaXRvciBpcyBsb2NhdGVkIDxicj4gLS0gNSBkaWdpdCBpZCBjb2RlIGZvciBjb3VudGllcyAoemVybyBpcyBvZnRlbiB0aGUgZmlyc3QgdmFsdWUgYW5kIHNvbWV0aW1lcyBpcyBub3Qgc2hvd24pIDxicj4gLS0gdGhlIGZpcnN0IDIgbnVtYmVycyBpbmRpY2F0ZSB0aGUgc3RhdGUgPGJyPiAtLSB0aGUgbGFzdCB0aHJlZSBudW1iZXJzIGluZGljYXRlIHRoZSBjb3VudHkgPGJyPiAgKipFeGFtcGxlKio6IEFsYWJhbWEncyBzdGF0ZSBjb2RlIGlzIDAxIGJlY2F1c2UgaXQgaXMgZmlyc3QgYWxwaGFiZXRpY2FsbHkgPGJyPiAobm90ZTogQWxhc2thIGFuZCBIYXdhaWkgYXJlIG5vdCBpbmNsdWRlZCBiZWNhdXNlIHRoZXkgYXJlIG5vdCBwYXJ0IG9mIHRoZSBjb250aWd1b3VzIFVTKSAgCioqTGF0KiogfCBMYXRpdHVkZSBvZiB0aGUgbW9uaXRvciBpbiBkZWdyZWVzICAKKipMb24qKiB8IExvbmdpdHVkZSBvZiB0aGUgbW9uaXRvciBpbiBkZWdyZWVzICAKKipzdGF0ZSoqIHwgU3RhdGUgd2hlcmUgdGhlIG1vbml0b3IgaXMgbG9jYXRlZAoqKmNvdW50eSoqIHwgQ291bnR5IHdoZXJlIHRoZSBtb25pdG9yIGlzIGxvY2F0ZWQKKipjaXR5KiogfCBDaXR5IHdoZXJlIHRoZSBtb25pdG9yIGlzIGxvY2F0ZWQKKipDTUFRKiogIHwgRXN0aW1hdGVkIHZhbHVlcyBvZiBhaXIgcG9sbHV0aW9uIGZyb20gYSBjb21wdXRhdGlvbmFsIG1vZGVsIGNhbGxlZCBbKipDb21tdW5pdHkgTXVsdGlzY2FsZSBBaXIgUXVhbGl0eSAoQ01BUSkqKl0oaHR0cHM6Ly93d3cuZXBhLmdvdi9jbWFxKXt0YXJnZXQ9Il9ibGFuayJ9IDxicj4gLS0gIEEgbW9uaXRvcmluZyBzeXN0ZW0gdGhhdCBzaW11bGF0ZXMgdGhlIHBoeXNpY3Mgb2YgdGhlIGF0bW9zcGhlcmUgdXNpbmcgY2hlbWlzdHJ5IGFuZCB3ZWF0aGVyIGRhdGEgdG8gcHJlZGljdCB0aGUgYWlyIHBvbGx1dGlvbiA8YnI+IC0tICoqKkRvZXMgbm90IHVzZSBhbnkgb2YgdGhlIFBNfjIuNX4gZ3JhdmltZXRyaWMgbW9uaXRvcmluZyBkYXRhLioqKiAoVGhlcmUgaXMgYSB2ZXJzaW9uIHRoYXQgZG9lcyB1c2UgdGhlIGdyYXZpbWV0cmljIG1vbml0b3JpbmcgZGF0YSwgYnV0IG5vdCB0aGlzIG9uZSEpIDxicj4gLS0gRGF0YSBmcm9tIHRoZSBFUEEKKip6Y3RhKiogfCBbWmlwIENvZGUgVGFidWxhdGlvbiBBcmVhXShodHRwczovL3d3dzIuY2Vuc3VzLmdvdi9nZW8vcGRmcy9lZHVjYXRpb24vYnJvY2h1cmVzL1pDVEFzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSB3aGVyZSB0aGUgbW9uaXRvciBpcyBsb2NhdGVkIDxicj4gLS0gUG9zdGFsIFppcCBjb2RlcyBhcmUgY29udmVydGVkIGludG8gImdlbmVyYWxpemVkIGFyZWFsIHJlcHJlc2VudGF0aW9ucyIgdGhhdCBhcmUgbm9uLW92ZXJsYXBwaW5nICA8YnI+IC0tIERhdGEgZnJvbSB0aGUgMjAxMCBDZW5zdXMgIAoqKnpjdGFfYXJlYSoqIHwgTGFuZCBhcmVhIG9mIHRoZSB6aXAgY29kZSBhcmVhIGluIG1ldGVycyBzcXVhcmVkICA8YnI+IC0tIERhdGEgZnJvbSB0aGUgMjAxMCBDZW5zdXMgIAoqKnpjdGFfcG9wKiogfCBQb3B1bGF0aW9uIGluIHRoZSB6aXAgY29kZSBhcmVhICA8YnI+IC0tIERhdGEgZnJvbSB0aGUgMjAxMCBDZW5zdXMgIAoqKmltcF9hNTAwKiogfCBJbXBlcnZpb3VzIHN1cmZhY2UgbWVhc3VyZSA8YnI+IC0tIFdpdGhpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDUwMCBtZXRlcnMgYXJvdW5kIHRoZSBtb25pdG9yIDxicj4gLS0gSW1wZXJ2aW91cyBzdXJmYWNlIGFyZSByb2FkcywgY29uY3JldGUsIHBhcmtpbmcgbG90cywgYnVpbGRpbmdzIDxicj4gLS0gVGhpcyBpcyBhIG1lYXN1cmUgb2YgZGV2ZWxvcG1lbnQgCioqaW1wX2ExMDAwKiogfCBJbXBlcnZpb3VzIHN1cmZhY2UgbWVhc3VyZSA8YnI+IC0tICBXaXRoaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAxMDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IKKippbXBfYTUwMDAqKiB8IEltcGVydmlvdXMgc3VyZmFjZSBtZWFzdXJlIDxicj4gLS0gIFdpdGhpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDUwMDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciAgCioqaW1wX2ExMDAwMCoqIHwgSW1wZXJ2aW91cyBzdXJmYWNlIG1lYXN1cmUgPGJyPiAtLSAgV2l0aGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTAwMDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciAgIAoqKmltcF9hMTUwMDAqKiB8IEltcGVydmlvdXMgc3VyZmFjZSBtZWFzdXJlIDxicj4gLS0gIFdpdGhpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDE1MDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgIAoqKmNvdW50eV9hcmVhKiogfCBMYW5kIGFyZWEgb2YgdGhlIGNvdW50eSBvZiB0aGUgbW9uaXRvciBpbiBtZXRlcnMgc3F1YXJlZCAgCioqY291bnR5X3BvcCoqIHwgUG9wdWxhdGlvbiBvZiB0aGUgY291bnR5IG9mIHRoZSBtb25pdG9yICAKKipMb2dfZGlzdF90b19wcmlzZWMqKiB8IExvZyAoTmF0dXJhbCBsb2cpIGRpc3RhbmNlIHRvIGEgcHJpbWFyeSBvciBzZWNvbmRhcnkgcm9hZCBmcm9tIHRoZSBtb25pdG9yIDxicj4gLS0gSGlnaHdheSBvciBtYWpvciByb2FkICAKKipsb2dfcHJpX2xlbmd0aF81MDAwKiogfCBDb3VudCBvZiBwcmltYXJ5IHJvYWQgbGVuZ3RoIGluIG1ldGVycyBpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDUwMDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpIDxicj4gLS0gSGlnaHdheXMgb25seSAgCioqbG9nX3ByaV9sZW5ndGhfMTAwMDAqKiB8IENvdW50IG9mIHByaW1hcnkgcm9hZCBsZW5ndGggaW4gbWV0ZXJzIGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTAwMDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpIDxicj4gLS0gSGlnaHdheXMgb25seSAgCioqbG9nX3ByaV9sZW5ndGhfMTUwMDAqKiB8IENvdW50IG9mIHByaW1hcnkgcm9hZCBsZW5ndGggaW4gbWV0ZXJzIGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTUwMDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpIDxicj4gLS0gSGlnaHdheXMgb25seSAgCioqbG9nX3ByaV9sZW5ndGhfMjUwMDAqKiB8IENvdW50IG9mIHByaW1hcnkgcm9hZCBsZW5ndGggaW4gbWV0ZXJzIGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMjUwMDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpIDxicj4gLS0gSGlnaHdheXMgb25seSAgCioqbG9nX3ByaXNlY19sZW5ndGhfNTAwKiogfCBDb3VudCBvZiBwcmltYXJ5IGFuZCBzZWNvbmRhcnkgcm9hZCBsZW5ndGggaW4gbWV0ZXJzIGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgNTAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSAgPGJyPiAtLSBIaWdod2F5IGFuZCBzZWNvbmRhcnkgcm9hZHMgIAoqKmxvZ19wcmlzZWNfbGVuZ3RoXzEwMDAqKiB8IENvdW50IG9mIHByaW1hcnkgYW5kIHNlY29uZGFyeSByb2FkIGxlbmd0aCBpbiBtZXRlcnMgaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAxMDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSAgPGJyPiAtLSBIaWdod2F5IGFuZCBzZWNvbmRhcnkgcm9hZHMgIAoqKmxvZ19wcmlzZWNfbGVuZ3RoXzUwMDAqKiB8IENvdW50IG9mIHByaW1hcnkgYW5kIHNlY29uZGFyeSByb2FkIGxlbmd0aCBpbiBtZXRlcnMgaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiA1MDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSAgPGJyPiAtLSBIaWdod2F5IGFuZCBzZWNvbmRhcnkgcm9hZHMgIAoqKmxvZ19wcmlzZWNfbGVuZ3RoXzEwMDAwKiogfCBDb3VudCBvZiBwcmltYXJ5IGFuZCBzZWNvbmRhcnkgcm9hZCBsZW5ndGggaW4gbWV0ZXJzIGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTAwMDAgbWV0ZXJzIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpICA8YnI+IC0tIEhpZ2h3YXkgYW5kIHNlY29uZGFyeSByb2FkcyAgCioqbG9nX3ByaXNlY19sZW5ndGhfMTUwMDAqKiB8IENvdW50IG9mIHByaW1hcnkgYW5kIHNlY29uZGFyeSByb2FkIGxlbmd0aCBpbiBtZXRlcnMgaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAxNTAwMCBtZXRlcnMgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgIDxicj4gLS0gSGlnaHdheSBhbmQgc2Vjb25kYXJ5IHJvYWRzICAKKipsb2dfcHJpc2VjX2xlbmd0aF8yNTAwMCoqIHwgQ291bnQgb2YgcHJpbWFyeSBhbmQgc2Vjb25kYXJ5IHJvYWQgbGVuZ3RoIGluIG1ldGVycyBpbiBhIGNpcmNsZSB3aXRoIGEgcmFkaXVzIG9mIDI1MDAwIG1ldGVycyBhcm91bmQgdGhlIG1vbml0b3IgKE5hdHVyYWwgbG9nKSAgPGJyPiAtLSBIaWdod2F5IGFuZCBzZWNvbmRhcnkgcm9hZHMgICAgICAKKipsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMTAwMDAqKiB8IFRvbnMgb2YgZW1pc3Npb25zIGZyb20gbWFqb3Igc291cmNlcyBkYXRhIGJhc2UgKGFubnVhbCBkYXRhKSBzdW0gb2YgYWxsIHNvdXJjZXMgd2l0aGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMTAwMDAgbWV0ZXJzIG9mIGRpc3RhbmNlIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpICAgIAoqKmxvZ19uZWlfMjAwOF9wbTI1X3N1bV8xNTAwMCoqIHwgVG9ucyBvZiBlbWlzc2lvbnMgZnJvbSBtYWpvciBzb3VyY2VzIGRhdGEgYmFzZSAoYW5udWFsIGRhdGEpIHN1bSBvZiBhbGwgc291cmNlcyB3aXRoaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAxNTAwMCBtZXRlcnMgb2YgZGlzdGFuY2UgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgICAgIAoqKmxvZ19uZWlfMjAwOF9wbTI1X3N1bV8yNTAwMCoqIHwgVG9ucyBvZiBlbWlzc2lvbnMgZnJvbSBtYWpvciBzb3VyY2VzIGRhdGEgYmFzZSAoYW5udWFsIGRhdGEpIHN1bSBvZiBhbGwgc291cmNlcyB3aXRoaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAyNTAwMCBtZXRlcnMgb2YgZGlzdGFuY2UgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgICAgIAoqKmxvZ19uZWlfMjAwOF9wbTEwX3N1bV8xMDAwMCoqIHwgVG9ucyBvZiBlbWlzc2lvbnMgZnJvbSBtYWpvciBzb3VyY2VzIGRhdGEgYmFzZSAoYW5udWFsIGRhdGEpIHN1bSBvZiBhbGwgc291cmNlcyB3aXRoaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAxMDAwMCBtZXRlcnMgb2YgZGlzdGFuY2UgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgICAgICAKKipsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMTUwMDAqKnwgVG9ucyBvZiBlbWlzc2lvbnMgZnJvbSBtYWpvciBzb3VyY2VzIGRhdGEgYmFzZSAoYW5udWFsIGRhdGEpIHN1bSBvZiBhbGwgc291cmNlcyB3aXRoaW4gYSBjaXJjbGUgd2l0aCBhIHJhZGl1cyBvZiAxNTAwMCBtZXRlcnMgb2YgZGlzdGFuY2UgYXJvdW5kIHRoZSBtb25pdG9yIChOYXR1cmFsIGxvZykgICAgICAKKipsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMjUwMDAqKiB8IFRvbnMgb2YgZW1pc3Npb25zIGZyb20gbWFqb3Igc291cmNlcyBkYXRhIGJhc2UgKGFubnVhbCBkYXRhKSBzdW0gb2YgYWxsIHNvdXJjZXMgd2l0aGluIGEgY2lyY2xlIHdpdGggYSByYWRpdXMgb2YgMjUwMDAgbWV0ZXJzIG9mIGRpc3RhbmNlIGFyb3VuZCB0aGUgbW9uaXRvciAoTmF0dXJhbCBsb2cpICAgICAgCioqcG9wZGVuc19jb3VudHkqKiB8IFBvcHVsYXRpb24gZGVuc2l0eSAobnVtYmVyIG9mIHBlb3BsZSBwZXIga2lsb21ldGVyIHNxdWFyZWQgYXJlYSBvZiB0aGUgY291bnR5KQoqKnBvcGRlbnNfemN0YSoqIHwgUG9wdWxhdGlvbiBkZW5zaXR5IChudW1iZXIgb2YgcGVvcGxlIHBlciBraWxvbWV0ZXIgc3F1YXJlZCBhcmVhIG9mIHpjdGEpCioqbm9ocyoqIHwgUGVyY2VudGFnZSBvZiBwZW9wbGUgaW4gemN0YSBhcmVhIHdoZXJlIHRoZSBtb25pdG9yIGlzIHRoYXQgKipkbyBub3QgaGF2ZSBhIGhpZ2ggc2Nob29sIGRlZ3JlZSoqIDxicj4gLS0gRGF0YSBmcm9tIHRoZSBDZW5zdXMKKipzb21laHMqKiB8IFBlcmNlbnRhZ2Ugb2YgcGVvcGxlIGluIHpjdGEgYXJlYSB3aGVyZSB0aGUgbW9uaXRvciB3aG9zZSBoaWdoZXN0IGZvcm1hbCBlZHVjYXRpb25hbCBhdHRhaW5tZW50IHdhcyAqKnNvbWUgaGlnaCBzY2hvb2wgZWR1Y2F0aW9uKiogPGJyPiAtLSBEYXRhIGZyb20gdGhlIENlbnN1cwoqKmhzKiogfCBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB6Y3RhIGFyZWEgd2hlcmUgdGhlIG1vbml0b3Igd2hvc2UgaGlnaGVzdCBmb3JtYWwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCB3YXMgY29tcGxldGluZyBhICoqaGlnaCBzY2hvb2wgZGVncmVlKiogPGJyPiAtLSBEYXRhIGZyb20gdGhlIENlbnN1cyAgCioqc29tZWNvbGxlZ2UqKiB8IFBlcmNlbnRhZ2Ugb2YgcGVvcGxlIGluIHpjdGEgYXJlYSB3aGVyZSB0aGUgbW9uaXRvciB3aG9zZSBoaWdoZXN0IGZvcm1hbCBlZHVjYXRpb25hbCBhdHRhaW5tZW50IHdhcyBjb21wbGV0aW5nICoqc29tZSBjb2xsZWdlIGVkdWNhdGlvbioqIDxicj4gLS0gRGF0YSBmcm9tIHRoZSBDZW5zdXMgCioqYXNzb2NpYXRlKiogfCBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB6Y3RhIGFyZWEgd2hlcmUgdGhlIG1vbml0b3Igd2hvc2UgaGlnaGVzdCBmb3JtYWwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCB3YXMgY29tcGxldGluZyBhbiAqKmFzc29jaWF0ZSBkZWdyZWUqKiA8YnI+IC0tIERhdGEgZnJvbSB0aGUgQ2Vuc3VzIAoqKmJhY2hlbG9yKiogfCBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB6Y3RhIGFyZWEgd2hlcmUgdGhlIG1vbml0b3Igd2hvc2UgaGlnaGVzdCBmb3JtYWwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCB3YXMgYSAqKmJhY2hlbG9yJ3MgZGVncmVlKiogPGJyPiAtLSBEYXRhIGZyb20gdGhlIENlbnN1cyAKKipncmFkKiogfCBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB6Y3RhIGFyZWEgd2hlcmUgdGhlIG1vbml0b3Igd2hvc2UgaGlnaGVzdCBmb3JtYWwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCB3YXMgYSAqKmdyYWR1YXRlIGRlZ3JlZSoqIDxicj4gLS0gRGF0YSBmcm9tIHRoZSBDZW5zdXMgCioqcG92KiogfCBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB6Y3RhIGFyZWEgd2hlcmUgdGhlIG1vbml0b3IgaXMgdGhhdCBsaXZlZCBpbiBbKipwb3ZlcnR5KipdKGh0dHBzOi8vYXNwZS5oaHMuZ292LzIwMDgtaGhzLXBvdmVydHktZ3VpZGVsaW5lcykgaW4gMjAwOCAtIG9yIHdvdWxkIGl0IGhhdmUgYmVlbiAyMDA3IGd1aWRlbGluZXM/P2h0dHBzOi8vYXNwZS5oaHMuZ292LzIwMDctaGhzLXBvdmVydHktZ3VpZGVsaW5lcyA8YnI+IC0tIERhdGEgZnJvbSB0aGUgQ2Vuc3VzICAKKipoc19vcmxlc3MqKiB8ICBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB6Y3RhIGFyZWEgd2hlcmUgdGhlIG1vbml0b3Igd2hvc2UgaGlnaGVzdCBmb3JtYWwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCB3YXMgYSAqKmhpZ2ggc2Nob29sIGRlZ3JlZSBvciBsZXNzKiogKHN1bSBvZiBub2hzLCBzb21laHMsIGFuZCBocykgIAoqKnVyYzIwMTMqKiB8IFsyMDEzIFVyYmFuLXJ1cmFsIGNsYXNzaWZpY2F0aW9uXShodHRwczovL3d3dy5jZGMuZ292L25jaHMvZGF0YS9zZXJpZXMvc3JfMDIvc3IwMl8xNjYucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IG9mIHRoZSBjb3VudHkgd2hlcmUgdGhlIG1vbml0b3IgaXMgbG9jYXRlZCA8YnI+IC0tIDYgY2F0ZWdvcnkgdmFyaWFibGUgLSAxIGlzIHRvdGFsbHkgdXJiYW4gNiBpcyBjb21wbGV0ZWx5IHJ1cmFsIDxicj4gIC0tIERhdGEgZnJvbSB0aGUgTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljc10oaHR0cHM6Ly93d3cuY2RjLmdvdi9uY2hzL2luZGV4Lmh0bSl7dGFyZ2V0PSJfYmxhbmsifSAgICAgCioqdXJjMjAwNioqIHwgWzIwMDYgVXJiYW4tcnVyYWwgY2xhc3NpZmljYXRpb25dKGh0dHBzOi8vd3d3LmNkYy5nb3YvbmNocy9kYXRhL3Nlcmllcy9zcl8wMi9zcjAyXzE1NC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gb2YgdGhlIGNvdW50eSB3aGVyZSB0aGUgbW9uaXRvciBpcyBsb2NhdGVkIDxicj4gLS0gNiBjYXRlZ29yeSB2YXJpYWJsZSAtIDEgaXMgdG90YWxseSB1cmJhbiA2IGlzIGNvbXBsZXRlbHkgcnVyYWwgPGJyPiAtLSBEYXRhIGZyb20gdGhlIFtOYXRpb25hbCBDZW50ZXIgZm9yIEhlYWx0aCBTdGF0aXN0aWNzXShodHRwczovL3d3dy5jZGMuZ292L25jaHMvaW5kZXguaHRtKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAKKiphb2QqKiB8IEFlcm9zb2wgT3B0aWNhbCBEZXB0aCBtZWFzdXJlbWVudCBmcm9tIGEgTkFTQSBzYXRlbGxpdGUgPGJyPiAtLSBiYXNlZCBvbiB0aGUgZGlmZnJhY3Rpb24gb2YgYSBsYXNlciA8YnI+IC0tIHVzZWQgYXMgYSBwcm94eSBvZiBwYXJ0aWN1bGF0ZSBwb2xsdXRpb24gPGJyPiAtLSB1bml0LWxlc3MgLSBoaWdoZXIgdmFsdWUgaW5kaWNhdGVzIG1vcmUgcG9sbHV0aW9uIDxicj4gLS0gRGF0YSBmcm9tIE5BU0EgIAoKPC9kZXRhaWxzPgoKCk1hbnkgb2YgdGhlc2UgcHJlZGljdG9yIHZhcmlhYmxlcyBoYXZlIHRvIGRvIHdpdGggdGhlIGNpcmN1bGFyIGFyZWEgYXJvdW5kIHRoZSBtb25pdG9yIGNhbGxlZCB0aGUgImJ1ZmZlciIuIFRoZXNlIGFyZSBpbGx1c3RyYXRlZCBpbiB0aGUgZm9sbG93aW5nIGZpZ3VyZToKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDBweCIsfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAicmVncmVzc2lvbi5wbmciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wdWJtZWQvMTUyOTI5MDYpXXt0YXJnZXQ9Il9ibGFuayJ9CgoKCiMjIERhdGEgSW1wb3J0CgpXZSBoYXZlIG9uZSBDU1YgZmlsZSB0aGF0IGNvbnRhaW5zIGJvdGggb3VyIHNpbmdsZSAqKm91dGNvbWUgdmFyaWFibGUqKiBhbmQgYWxsIG9mIG91ciAqKnByZWRpY3RvciB2YXJpYWJsZXMqKi4KCkxldCdzIGltcG9ydCBvdXIgZGF0YSBpbnRvIFIgbm93IHNvIHRoYXQgd2UgY2FuIGV4cGxvcmUgdGhlIGRhdGEgZnVydGhlci4gV2Ugd2lsbCBjYWxsIG91ciBkYXRhIG9iamVjdCBgcG1gIGZvciBwYXJ0aWN1bGF0ZSBtYXR0ZXIuCgpgYGB7cn0KcG0gPC1yZWFkcjo6cmVhZF9jc3YoaGVyZSgiZG9jcyIsICJwbTI1X2RhdGEuY3N2IikpCmBgYAoKIyMgRGF0YSBFeHBsb3JhdGlvbiBhbmQgV3JhbmdsaW5nCgpUaGUgZmlyc3Qgc3RlcCBpbiBwZXJmb3JtaW5nIGEgbWFjaGluZSBsZWFybmluZyBhbmFseXNpcyBpcyB0byBleHBsb3JlIHRoZSBkYXRhIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSB2YXJpYWJsZXMgIGluY2x1ZGVkIGluIHRoZSBkYXRhLCBhcyB3ZSBtYXkgbGVhcm4gYWJvdXQgaW1wb3J0YW50IGRldGFpbHMgYWJvdXQgdGhlIGRhdGEgdGhhdCB3ZSBzaG91bGQga2VlcCBpbiBtaW5kIGFzIHdlIHRyeSB0byBwcmVkaWN0IG91ciBvdXRjb21lIHZhcmlhYmxlLgoKRmlyc3QgbGV0J3MganVzdCBnZXQgYSBnZW5lcmFsIHNlbnNlIG9mIG91ciBkYXRhLiBXZSBjYW4gZG8gdGhhdCB1c2luZyB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSAoaXQgaXMgYWxzbyBpbiB0aGUgYHRpYmJsZWAgcGFja2FnZSkuCgpXZSB3aWxsIGFsc28gdXNlIHRoZSBgJT4lYCBwaXBlIHdoaWNoIGNhbiBiZSB1c2VkIHRvIGRlZmluZSB0aGUgaW5wdXQgZm9yIGxhdGVyIHNlcXVlbnRpYWwgc3RlcHMuIFRoaXMgd2lsbCBtYWtlIG1vcmUgc2Vuc2Ugd2hlbiB3ZSBoYXZlIG11bHRpcGxlIHNlcXVlbnRpYWwgc3RlcHMgdXNpbmcgdGhlIHNhbWUgZGF0YSBvYmplY3QuIFRvIHVzZSB0aGUgcGlwZSBub3RhdGlvbiB3ZSBuZWVkIHRvIGluc3RhbGwgYW5kIGxvYWQgZHBseXIgYXMgd2VsbC4KCkZvciBleGFtcGxlIGhlcmUgd2Ugd2lsbCBmaXJzdCBncmFiIHRoZSBgcG1gIGRhdGEgb2JqZWN0LCB0aGVuIHdlIHVzZSB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gb24gaXQgYmFzZWQgb24gdGhlIHBpcGUgbm90YXRpb24uCgojIyMjIHsuc2Nyb2xsYWJsZSB9CgpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpwbSAlPiUKICBkcGx5cjo6Z2xpbXBzZSgpCmBgYAoKIyMjIwoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSA4NzYgbW9uaXRvcnMgYW5kIHRoYXQgd2UgaGF2ZSA1MCB0b3RhbCB2YXJpYWJsZXMgLSBvbmUgb2Ygd2hpY2ggaXMgdGhlIG91dGNvbWUuIEluIHRoaXMgY2FzZSBvdXIgb3V0Y29tZSB2YXJpYWJsZSBpcyBjYWxsZWQgYHZhbHVlYC4gCgpOb3RpY2UgdGhhdCBzb21lIG9mIHRoZSB2YXJpYWJsZXMgdGhhdCB3ZSB3b3VsZCB0aGluayBvZiBhcyBmYWN0b3JzIChjYXRlZ29yaWNhbCkgYXJlIGN1cnJlbnRseSBvZiBjbGFzcyBkb3VibGUgYXMgaW5kaWNhdGVkIGJ5IHRoZSBgPGRibD5gIGp1c3QgdG8gdGhlIHJpZ2h0IG9mIHRoZSBjb2x1bW4gbmFtZXMvdmFyaWFibGUgbmFtZXMgaW4gdGhlIGBnbGltcHNlKClgIG91dHB1dC4gRm9yIGV4YW1wbGUgdGhlIG1vbml0b3IgSUQgKGlkKSwgdGhlIEZlZGVyYWwgSW5mb3JtYXRpb24gUHJvY2Vzc2luZyBTdGFuZGFyZCBudW1iZXIgZm9yIHRoZSBjb3VudHkgd2hlcmUgdGhlIG1vbml0b3Igd2FzIGxvY2F0ZWQgKGZpcHMpLCBhcyB3ZWxsIGFzIHRoZSB6Y3RhCgpMZXQncyBjb252ZXJ0IHRoZXNlIHZhcmlhYmxlcyBpbnRvIGZhY3RvcnMuIFdlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBgbXV0YXRlX2F0KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgYW5kIHRoZSBgYXMuZmFjdG9yKClgIGJhc2UgZnVuY3Rpb24uIAoKSW4gdGhpcyBjYXNlIHdlIGFyZSBhbHNvIHVzaW5nIHRoZSBtYWdyaXR0ciBhc3NpZ25tZW50IHBpcGUgb3IgZG91YmxlIHBpcGUgdGhhdCBsb29rcyBsaWtlIHRoaXMgYCU8PiVgIG9mIHRoZSBgbWFncml0dHJgIHBhY2thZ2UuIFRoaXMgYWxsb3dzIHVzIHVzZSB0aGUgYHBtYCBkYXRhIGFzIGlucHV0IGJ1dCBhbHNvIHJlYXNzaWduIHRoZSBvdXRwdXQgdG8gdGhlIHNhbWUgZGF0YSBvYmplY3QgbmFtZS4KCgojIyMjIHsuc2Nyb2xsYWJsZSB9CgpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpwbSAlPD4lCiAgZHBseXI6Om11dGF0ZV9hdCh2YXJzKGlkLCBmaXBzLCB6Y3RhKSwgYXMuZmFjdG9yKSAKCmdsaW1wc2UocG0pCmBgYAoKIyMjIwoKR3JlYXQhIE5vdyB3ZSBjYW4gc2VlIHRoYXQgdGhlc2UgdmFyaWFibGVzIGFyZSBub3cgZmFjdG9ycyBhcyBpbmRpY2F0ZWQgYnkgYDxmY3Q+YCBhZnRlciB0aGUgdmFyaWFibGUgbmFtZS4KCiMjIyBQYWNrYWdlcyB0byBnZXQgYSBzZW5zZSBvZiB0aGUgZGF0YQoKVGhlIGBza2ltKClgIGZ1bmN0aW9uIG9mIHRoZSBgc2tpbXJgIHBhY2thZ2UgaXMgYWxzbyByZWFsbHkgaGVscGZ1bCBmb3IgZ2V0dGluZyBhIGdlbmVyYWwgc2Vuc2Ugb2YgeW91ciBkYXRhLgoKCiMjIyMgey5zY3JvbGxhYmxlIH0KCmBgYHtyfQojIFNjcm9sbCB0aHJvdWdoIHRoZSBvdXRwdXQhCnNraW0ocG0pCmBgYAoKIyMjIwpOb3RpY2UgaG93IHRoZXJlIGlzIGEgY29sdW1uIGNhbGxlZCBgbl9taXNzaW5nYCBhYm91dCB0aGUgbnVtYmVyIG9mIHZhbHVlcyB0aGF0IGFyZSBtaXNzaW5nLiBJdCBsb29rcyBsaWtlIG91ciBkYXRhIGlzIHZlcnkgY29tcGxldGUgYW5kIHdlIGRvIG5vdCBoYXZlIGFueSBtaXNzaW5nIGRhdGEuIFRoaXMgaXMgYWxzbyBpbmRpY2F0ZWQgYnkgdGhlIGBjb21wbGV0ZV9yYXRlYCB2YXJpYWJsZSwgd2hpY2ggc2hvd3MgdGhlIHJhdGlvIG9mIGNvbXBsZXRlbmVzcywgaW4gb3VyIGNhc2UgYWxsIHZhcmlhYmxlcyBoYXZlIGEgdmFsdWUgb2YgMSBpbmRpY2F0aW5nIHRoZXkgYXJlIGZ1bGx5IGNvbXBsZXRlLgoKVGhlIGBuX3VucWl1ZWAgY29sdW1uIHNob3dzIHVzIHRoZSBudW1iZXIgb2YgdW5pcXVlIHZhbHVlcyBmb3IgZWFjaCBvZiBvdXIgY29sdW1ucy4gV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSA0OSBzdGF0ZXMgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGEsIGFuZCB3ZSBrbm93IHRoYXQgdGhlIGRhdGEgc2hvdWxkIGJlIG9mIHRoZSBjb250aWd1b3VzIHN0YXRlcy4gTGV0J3MgdGFrZSBhIGxvb2sgdG8gc2VlIHdoaWNoIHN0YXRlcyBhcmUgaW5jbHVkZWQ6CgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQojIFNjcm9sbCB0aHJvdWdoIHRoZSBvdXRwdXQhCnBtICU+JSAKICBkaXN0aW5jdChzdGF0ZSkgJT4lCiAgcHJpbnQobiA9IDFlMykKYGBgCiMjIyMKCkxvb2tzIGxpa2UgIkRpc3RyaWN0IG9mIENvbHVtYmlhIiBpcyBiZWluZyBpbmNsdWRlZCBhcyBhIHN0YXRlLiBXZSBjYW4gc2VlIHRoYXQgaW5kZWVkIEFsYXNrYSBhbmQgSGF3YWlpIGFyZSBub3QgaW5jbHVkZWQgaW4gdGhlIGRhdGEuCgpIZXJlIGlzIGFub3RoZXIgbWV0aG9kIG9mIGxvb2tpbmcgYXQgdGhlIGRhdGEgdXNpbmcgdGhlIGBkZlN1bW1hcnkoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdW1tYXJ5dG9vbHNgcGFja2FnZS4gV2UgbmVlZCB0byBjb3B5IGFuZCBwYXN0ZSB0aGUgb3V0cHV0IGludG8gdGhlIHJtYXJrZG93bi4KCmBgYHtyLCBldmFsID0gRkFMU0V9CmRmU3VtbWFyeShwbSwgcGxhaW4uYXNjaWkgPSBGQUxTRSwgc3R5bGUgPSAiZ3JpZCIsIAogICAgICAgICAgZ3JhcGgubWFnbmlmID0gMC40NSwgIHRtcC5pbWcuZGlyID0gInRtcCIpCmBgYAoKPGRldGFpbHM+PHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIHRoZSBkZlN1bW1hcnkgdGFibGUgPC9zdW1tYXJ5PgoKCioqRGltZW5zaW9uczoqKiA4NzYgeCA1MCAgCioqRHVwbGljYXRlczoqKiAwICAKCistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgTm8gfCBWYXJpYWJsZSAgICAgICAgICAgICAgICAgICAgIHwgU3RhdHMgLyBWYWx1ZXMgICAgICAgICAgICAgICAgICAgICAgICAgICB8IEZyZXFzICglIG9mIFZhbGlkKSAgfCBHcmFwaCAgICAgICAgICAgICAgIHwgVmFsaWQgIHwgTWlzc2luZyB8Cis9PT09Kz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSs9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0rPT09PT09PT09PT09PT09PT09PT09Kz09PT09PT09PT09PT09PT09PT09PSs9PT09PT09PSs9PT09PT09PT0rCnwgMSAgfCBpZFwgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIDEwMDMuMDAxXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAhW10odG1wL2RzMDEwMS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbZmFjdG9yXSAgICAgICAgICAgICAgICAgICAgIHwgMlwuIDEwMjcuMDAwMVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIDEwMzMuMTAwMlwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIDEwNDkuMTAwM1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIDEwNTUuMDAxXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIDEwNjkuMDAwM1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIDEwNzMuMDAyM1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIDEwNzMuMTAwNVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIDEwNzMuMTAwOVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiAxMDczLjEwMVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA4NjYgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDg2NiAoOTguOSUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMiAgfCB2YWx1ZVwgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTAuOCAoMi42KVwgICAgICAgICAgICAgICAgICB8IDg3NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEwMi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMyA8IDExLjIgPCAyMy4yXCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjEgKDAuMikgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMyAgfCBmaXBzXCAgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIDEwMDNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAhW10odG1wL2RzMDEwMy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbZmFjdG9yXSAgICAgICAgICAgICAgICAgICAgIHwgMlwuIDEwMjdcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIDEwMzNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIDEwNDlcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIDEwNTVcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIDEwNjlcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIDEwNzNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDggKCAwLjklKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIDEwODlcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIDEwOTdcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDIgKCAwLjIlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiAxMTAxXCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA1NTkgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDg1OCAoOTguMCUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNCAgfCBsYXRcICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMzguNSAoNC42KVwgICAgICAgICAgICAgICAgICB8IDg3NiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEwNC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMjUuNSA8IDM5LjMgPCA0OC40XCAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA2LjYgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNSAgfCBsb25cICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogLTkxLjcgKDE1KVwgICAgICAgICAgICAgICAgICB8IDg3NiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEwNS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgLTEyNC4yIDwgLTg3LjUgPCAtNjhcICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxOC41ICgtMC4yKSAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNiAgfCBzdGF0ZVwgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIENhbGlmb3JuaWFcICAgICAgICAgICAgICAgICAgICAgICAgICB8IDg1ICggOS43JSlcICAgICAgICAgfCAhW10odG1wL2RzMDEwNi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbY2hhcmFjdGVyXSAgICAgICAgICAgICAgICAgIHwgMlwuIE9oaW9cICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDQ0ICggNS4wJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIElsbGlub2lzXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDM4ICggNC4zJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIEluZGlhbmFcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDM2ICggNC4xJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIE5vcnRoIENhcm9saW5hXCAgICAgICAgICAgICAgICAgICAgICB8IDM1ICggNC4wJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIFBlbm5zeWx2YW5pYVwgICAgICAgICAgICAgICAgICAgICAgICB8IDMyICggMy43JSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIE1pY2hpZ2FuXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDMwICggMy40JSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIEZsb3JpZGFcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDI5ICggMy4zJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIEdlb3JnaWFcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDI4ICggMy4yJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiBUZXhhc1wgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDI3ICggMy4xJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyAzOSBvdGhlcnMgXSAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDQ5MiAoNTYuMiUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNyAgfCBjb3VudHlcICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIEplZmZlcnNvblwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDE4ICggMi4xJSlcICAgICAgICAgfCAhW10odG1wL2RzMDEwNy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbY2hhcmFjdGVyXSAgICAgICAgICAgICAgICAgIHwgMlwuIENvb2tcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEyICggMS40JSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIEhhbWlsdG9uXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDExICggMS4zJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIExha2VcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDExICggMS4zJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIExvcyBBbmdlbGVzXCAgICAgICAgICAgICAgICAgICAgICAgICB8IDEwICggMS4xJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIFdheW5lXCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEwICggMS4xJSlcICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIFdhc2hpbmd0b25cICAgICAgICAgICAgICAgICAgICAgICAgICB8IDkgKCAxLjAlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIEN1eWFob2dhXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDcgKCAwLjglKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIEphY2tzb25cICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDcgKCAwLjglKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiBNYWRpc29uXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDcgKCAwLjglKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA0NjEgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDc3NCAoODguNCUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgOCAgfCBjaXR5XCAgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIE5vdCBpbiBhIGNpdHlcICAgICAgICAgICAgICAgICAgICAgICB8IDEwMyAoMTEuOCUpXCAgICAgICAgfCAhW10odG1wL2RzMDEwOC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbY2hhcmFjdGVyXSAgICAgICAgICAgICAgICAgIHwgMlwuIE5ldyBZb3JrXCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDkgKCAxLjAlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIENsZXZlbGFuZFwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDYgKCAwLjclKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIEJhbHRpbW9yZVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIENoaWNhZ29cICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIERldHJvaXRcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIE1pbHdhdWtlZVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIE5ldyBIYXZlblwgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIFBoaWxhZGVscGhpYVwgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiBTcHJpbmdmaWVsZFwgICAgICAgICAgICAgICAgICAgICAgICB8IDUgKCAwLjYlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA1OTcgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDcyMyAoODIuNSUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgOSAgfCBDTUFRXCAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogOC40ICgzKVwgICAgICAgICAgICAgICAgICAgICB8IDYwMSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEwOS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMS42IDwgOC42IDwgMjMuMVwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjcgKDAuNCkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTAgfCB6Y3RhXCAgICAgICAgICAgICAgICAgICAgICAgIHwgMVwuIDEwMjJcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAhW10odG1wL2RzMDExMC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbZmFjdG9yXSAgICAgICAgICAgICAgICAgICAgIHwgMlwuIDExMDNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDIgKCAwLjIlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgM1wuIDEyMDFcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNFwuIDE2MDhcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDIgKCAwLjIlKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNVwuIDE4MzJcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNlwuIDE4NDBcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgN1wuIDE4NjNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOFwuIDE5MDRcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOVwuIDIxMTNcICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTBcLiAyMTE5XCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEgKCAwLjElKVwgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgWyA4MzIgb3RoZXJzIF0gICAgICAgICAgICAgICAgICAgICAgICAgICB8IDg2NCAoOTguNiUpICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTEgfCB6Y3RhX2FyZWFcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTgzMTczNDgxLjkgKDU0MjU5ODg3OC41KVwgICB8IDg0MiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExMS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTU0NTkgPCAzNzY1MzU2MC41IDwgODE2NDgyMDYyNVwgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxNDU4MzY5MDYuNSAoMykgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTIgfCB6Y3RhX3BvcFwgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMjQyMjcuNiAoMTc3NzIuMilcICAgICAgICAgICB8IDgzNyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExMi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDIyMDE0IDwgOTUzOTdcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyNTIwNy44ICgwLjcpICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTMgfCBpbXBfYTUwMFwgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMjQuNyAoMTkuMylcICAgICAgICAgICAgICAgICB8IDgxNiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExMy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDI1LjEgPCA2OS42XCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzNi41ICgwLjgpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTQgfCBpbXBfYTEwMDBcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMjQuMyAoMTgpXCAgICAgICAgICAgICAgICAgICB8IDg2MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExNC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDI0LjUgPCA2Ny41XCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzMy4zICgwLjcpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTUgfCBpbXBfYTUwMDBcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTkuOSAoMTQuNylcICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExNS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMC4xIDwgMTkuMSA8IDc0LjZcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyMy4zICgwLjcpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTYgfCBpbXBfYTEwMDAwXCAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTUuOCAoMTMuOClcICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExNi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMC4xIDwgMTIuNCA8IDcyLjFcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxOS42ICgwLjkpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTcgfCBpbXBfYTE1MDAwXCAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTMuNCAoMTMuMSlcICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExNy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMC4xIDwgOS43IDwgNzEuMVwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxNy4zICgxKSAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTggfCBjb3VudHlfYXJlYVwgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMzc2ODcwMTk5Mi4xICg2MjEyODI5NTUzLjYpXCB8IDU2NCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExOC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMzM3MDM1MTIgPCAxNjkwODI2NTY2LjUgPCA1MTk0NzIyOTUwOVwgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxNzYxNjU1OTExLjUgKDEuNikgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMTkgfCBjb3VudHlfcG9wXCAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNjg3Mjk4LjQgKDEyOTM0ODguNylcICAgICAgICB8IDU2NCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDExOS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNzgzIDwgMjgwNzMwLjUgPCA5ODE4NjA1XCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA2NDIyMTEgKDEuOSkgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjAgfCBsb2dfZGlzdF90b19wcmlzZWNcICAgICAgICAgIHwgTWVhbiAoc2QpIDogNi4yICgxLjQpXCAgICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyMC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgLTEuNSA8IDYuNCA8IDEwLjVcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjcgKDAuMikgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjEgfCBsb2dfcHJpX2xlbmd0aF81MDAwXCAgICAgICAgIHwgTWVhbiAoc2QpIDogOS44ICgxLjEpXCAgICAgICAgICAgICAgICAgICB8IDU4NiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyMS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOC41IDwgMTAuMSA8IDEyXCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjIgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjIgfCBsb2dfcHJpX2xlbmd0aF8xMDAwMFwgICAgICAgIHwgTWVhbiAoc2QpIDogMTAuOSAoMS4xKVwgICAgICAgICAgICAgICAgICB8IDY4NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyMi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOS4yIDwgMTEuMiA8IDEzXCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyICgwLjEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjMgfCBsb2dfcHJpX2xlbmd0aF8xNTAwMFwgICAgICAgIHwgTWVhbiAoc2QpIDogMTEuNSAoMS4xKVwgICAgICAgICAgICAgICAgICB8IDcyNiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyMy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOS42IDwgMTEuNyA8IDEzLjZcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjUgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjQgfCBsb2dfcHJpX2xlbmd0aF8yNTAwMFwgICAgICAgIHwgTWVhbiAoc2QpIDogMTIuMiAoMS4xKVwgICAgICAgICAgICAgICAgICB8IDc4NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyNC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTAuMSA8IDEyLjUgPCAxNC40XCAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjQgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjUgfCBsb2dfcHJpc2VjX2xlbmd0aF81MDBcICAgICAgIHwgTWVhbiAoc2QpIDogNyAoMSlcICAgICAgICAgICAgICAgICAgICAgICB8IDM4MiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyNS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNi4yIDwgNi4yIDwgOS40XCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjYgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjYgfCBsb2dfcHJpc2VjX2xlbmd0aF8xMDAwXCAgICAgIHwgTWVhbiAoc2QpIDogOC42ICgwLjgpXCAgICAgICAgICAgICAgICAgICB8IDU5MSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyNi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNy42IDwgOC43IDwgMTAuNVwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxLjYgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjcgfCBsb2dfcHJpc2VjX2xlbmd0aF81MDAwXCAgICAgIHwgTWVhbiAoc2QpIDogMTEuMyAoMC44KVwgICAgICAgICAgICAgICAgICB8IDg1MiBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyNy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOC41IDwgMTEuNCA8IDEyLjhcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAwLjkgKDAuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjggfCBsb2dfcHJpc2VjX2xlbmd0aF8xMDAwMFwgICAgIHwgTWVhbiAoc2QpIDogMTIuNCAoMC43KVwgICAgICAgICAgICAgICAgICB8IDg2NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyOC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOS4yIDwgMTIuNSA8IDEzLjhcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxICgwLjEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMjkgfCBsb2dfcHJpc2VjX2xlbmd0aF8xNTAwMFwgICAgIHwgTWVhbiAoc2QpIDogMTMgKDAuNylcICAgICAgICAgICAgICAgICAgICB8IDg2OSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEyOS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgOS42IDwgMTMuMSA8IDE0LjRcICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxICgwLjEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzAgfCBsb2dfcHJpc2VjX2xlbmd0aF8yNTAwMFwgICAgIHwgTWVhbiAoc2QpIDogMTMuOCAoMC43KVwgICAgICAgICAgICAgICAgICB8IDg3MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzMC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMTAuMSA8IDEzLjkgPCAxNS4yXCAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxICgwLjEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzEgfCBsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMTAwMDBcIHwgTWVhbiAoc2QpIDogNCAoMi40KVwgICAgICAgICAgICAgICAgICAgICB8IDgyOCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzMS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDQuMyA8IDkuMVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjUgKDAuNikgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzIgfCBsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMTUwMDBcIHwgTWVhbiAoc2QpIDogNC43ICgyLjIpXCAgICAgICAgICAgICAgICAgICB8IDg1NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzMi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDUgPCA5LjRcICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjkgKDAuNSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzMgfCBsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMjUwMDBcIHwgTWVhbiAoc2QpIDogNS43ICgyLjEpXCAgICAgICAgICAgICAgICAgICB8IDg2MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzMy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDUuOSA8IDkuN1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjYgKDAuNCkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzQgfCBsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMTAwMDBcIHwgTWVhbiAoc2QpIDogNC4zICgyLjMpXCAgICAgICAgICAgICAgICAgICB8IDgyOSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzNC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDQuNiA8IDkuM1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjQgKDAuNSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzUgfCBsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMTUwMDBcIHwgTWVhbiAoc2QpIDogNS4xICgyLjIpXCAgICAgICAgICAgICAgICAgICB8IDg1NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzNS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDUuNCA8IDkuN1wgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjggKDAuNCkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzYgfCBsb2dfbmVpXzIwMDhfcG0xMF9zdW1fMjUwMDBcIHwgTWVhbiAoc2QpIDogNi4xICgyKVwgICAgICAgICAgICAgICAgICAgICB8IDg2MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzNi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDYuNCA8IDkuOVwgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyLjQgKDAuMykgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzcgfCBwb3BkZW5zX2NvdW50eVwgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNTUxLjggKDE3MTEuNSlcICAgICAgICAgICAgICB8IDU2NCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzNy5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMC4zIDwgMTU2LjcgPCAyNjgyMS45XCAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA0NzAgKDMuMSkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzggfCBwb3BkZW5zX3pjdGFcICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTI3OS43ICgyNzU3LjUpXCAgICAgICAgICAgICB8IDg0MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzOC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDYxMC4zIDwgMzA0MTguOFwgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxMjgxLjQgKDIuMikgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgMzkgfCBub2hzXCAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNyAoNy4yKVwgICAgICAgICAgICAgICAgICAgICB8IDIxNSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDEzOS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDUuMSA8IDEwMFwgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA2LjEgKDEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDAgfCBzb21laHNcICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTAuMiAoNi4yKVwgICAgICAgICAgICAgICAgICB8IDIzMCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0MC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDkuNCA8IDcyLjJcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA4ICgwLjYpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDEgfCBoc1wgICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMzAuMyAoMTEuNClcICAgICAgICAgICAgICAgICB8IDM0NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0MS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDMwLjggPCAxMDBcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxMi4zICgwLjQpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDIgfCBzb21lY29sbGVnZVwgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMjEuNiAoOC42KVwgICAgICAgICAgICAgICAgICB8IDI0MCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0Mi5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDIxLjMgPCAxMDBcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA3LjIgKDAuNCkgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDMgfCBhc3NvY2lhdGVcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNy4xICg0KVwgICAgICAgICAgICAgICAgICAgICB8IDE1NyBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0My5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDcuMSA8IDcxLjRcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAzLjkgKDAuNikgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDQgfCBiYWNoZWxvclwgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTQuOSAoOS43KVwgICAgICAgICAgICAgICAgICB8IDMwMSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0NC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDEyLjkgPCAxMDBcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxMC40ICgwLjcpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDUgfCBncmFkXCAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogOC45ICg4LjYpXCAgICAgICAgICAgICAgICAgICB8IDI0NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0NS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDYuNyA8IDEwMFwgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiA3LjEgKDEpICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDYgfCBwb3ZcICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMTUgKDExLjMpXCAgICAgICAgICAgICAgICAgICB8IDM0NSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0Ni5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDEyLjEgPCA2NS45XCAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxNC43ICgwLjgpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDcgfCBoc19vcmxlc3NcICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNDcuNSAoMTYuOClcICAgICAgICAgICAgICAgICB8IDQ2NCBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE0Ny5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMCA8IDQ4LjcgPCAxMDBcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyMS4yICgwLjQpICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDggfCB1cmMyMDEzXCAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMi45ICgxLjUpXCAgICAgICAgICAgICAgICAgICB8IDEgOiAyMDMgKDIzLjIlKVwgICAgfCAhW10odG1wL2RzMDE0OC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8IDIgOiAxNjMgKDE4LjYlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMSA8IDMgPCA2XCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDMgOiAyMjggKDI2LjAlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyICgwLjUpICAgICAgICAgICAgICAgICAgICAgICB8IDQgOiAxMjMgKDE0LjAlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgOiAxMDEgKDExLjUlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDYgOiAgNTggKCA2LjYlKSAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNDkgfCB1cmMyMDA2XCAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogMyAoMS41KVwgICAgICAgICAgICAgICAgICAgICB8IDEgOiAxOTUgKDIyLjMlKVwgICAgfCAhW10odG1wL2RzMDE0OS5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8IDIgOiAxNjIgKDE4LjUlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgMSA8IDMgPCA2XCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDMgOiAyMjEgKDI1LjIlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAyICgwLjUpICAgICAgICAgICAgICAgICAgICAgICB8IDQgOiAxMjcgKDE0LjUlKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDUgOiAxMTUgKDEzLjElKVwgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDYgOiAgNTYgKCA2LjQlKSAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCnwgNTAgfCBhb2RcICAgICAgICAgICAgICAgICAgICAgICAgIHwgTWVhbiAoc2QpIDogNDMuNyAoMTkuNilcICAgICAgICAgICAgICAgICB8IDU4MSBkaXN0aW5jdCB2YWx1ZXMgfCAhW10odG1wL2RzMDE1MC5wbmcpIHwgODc2XCAgIHwgMFwgICAgICB8CnwgICAgfCBbbnVtZXJpY10gICAgICAgICAgICAgICAgICAgIHwgbWluIDwgbWVkIDwgbWF4OlwgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgKDEwMCUpIHwgKDAlKSAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgNSA8IDQwLjIgPCAxNDNcICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CnwgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgSVFSIChDVikgOiAxOCAoMC40KSAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgIHwgICAgICAgICB8CistLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLSstLS0tLS0tLS0rCgo8L2RldGFpbHM+CgpXZSBjYW4gc2VlIHRoYXQgZm9yIG1hbnkgdmFyaWFibGVzIHRoZXJlIGFyZSBtYW55IGxvdyB2YWx1ZXMgYXMgdGhlIGRpc3RyaWJ1dGlvbiBzaG93cyB0d28gcGVha3MsIG9uZSBuZWFyIHplcm8gYW5kIGFub3RoZXIgd2l0aCBhIGhpZ2hlciB2YWx1ZS4gVGhpcyBpcyB0cnVlIGZvciB0aGUgaW1wIHZhcmlhYmxlcyAobWVhc3VyZXMgb2YgZGV2ZWxvcG1lbnQpLCB0aGUgbmVpIHZhcmlhYmxlcyAobWVhc3VyZXMgb2YgZW1pc3Npb24gc291cmNlcykgYW5kIHRoZSByb2FkIGRlbnNpdHkgdmFyaWFibGVzLiBXZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGUgcmFuZ2Ugb2Ygc29tZSBvZiB0aGUgdmFyaWFibGVzIGlzIHZlcnkgbGFyZ2UsIGluIHBhcnRpY3VsYXIgdGhlIGFyZWEgYW5kIHBvcHVsYXRpb24gcmVsYXRlZCB2YXJpYWJsZXMuCgojIyMgRXZhbHVhdGUgY29ycmVsYXRpb24gYW1vbmcgcG9zc2libGUgcHJlZGljdG9ycwpJbiBwcmVkaWN0aW9uIGFuYWx5c2VzLCBpdCBpcyBhbHNvIHVzZWZ1bCB0byBldmFsdWF0ZSBpZiBhbnkgb2YgdGhlIHZhcmlhYmxlcyBhcmUgY29ycmVsYXRlZC4KCkludHVpdGl2ZWx5IHdlIGNhbiBleHBlY3Qgc29tZSBvZiBvdXIgdmFyaWFibGVzIHRvIGJlIGNvcnJlbGF0ZWQuCgpMZXQncyBmaXJzdCB0YWtlIGEgbG9vayBhdCBhbGwgb2Ygb3VyIG51bWVyaWMgdmFyaWFiZWxzIHdpdGggdGhlYGNvcnJwbG90YCBwYWNrYWdlOgpUaGUgYGNvcnJwbG90YCBwYWNrYWdlIGlzIGFub3RoZXIgb3B0aW9uIHRvIGxvb2sgYXQgY29ycmVsYXRpb24gYW1vbmcgcG9zc2libGUgcHJlZGljdG9ycy4gVGhpcyBpcyBhIGdyZWF0IG9wdGlvbiBpZiB3ZSBoYXZlIG1hbnkgcHJlZGljdG9ycy4gCkZpcnN0IHdlIG5lZWQgdG8gY3JlYXRlIGEgY29ycmVsYXRpb24gbWF0cml4IHVzaW5nIHRoZSBgY29yKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RhdHNgIHBhY2thZ2UgKHdoaWNoIGlzIGxvYWRlZCBhdXRvbWF0aWNhbGx5KS4KCmBgYHtyfQojbGlicmFyeShSQ29sb3JCcmV3ZXIpICNuZWVkIHRoaXMgcGFja2FnZSBmb3IgdGhlIGNvbG9yClBNX2NvciA8LSBjb3IocG0gJT4lIGRwbHlyOjpzZWxlY3RfaWYoaXMubnVtZXJpYykpCmNvcnJwbG90Ojpjb3JycGxvdChQTV9jb3IsIHRsLmNleCA9IDAuNSkKCmNvcnJwbG90KGFicyhQTV9jb3IpLCBvcmRlciA9ICJBT0UiLCB0bC5jZXggPSAwLjUsICBjbC5saW0gPSBjKDAsIDEpKQoKCmNvcnJwbG90KFBNX2NvciwgZGlhZyA9IEZBTFNFLCBvcmRlciA9ICJGUEMiLAogICAgICAgICB0bC5wb3MgPSAidGQiLCB0bC5jZXggPSAwLjUsIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiLCBjb2wgPSBicmV3ZXIucGFsKG4gPSA4LCBuYW1lID0gIlB1T3IiKSkKCmNvcnJwbG90KFBNX2NvciwgZGlhZyA9IEZBTFNFLAogICAgICAgICB0bC5wb3MgPSAidGQiLCB0bC5jZXggPSAwLjUsIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiKQoKYGBgCgogVXNpbmcgYGdnY29ycGxvdGAgcGFja2FnZQpgYGB7cn0KZ2djb3JycGxvdChQTV9jb3IsIGhjLm9yZGVyID0gVFJVRSwgdHlwZSA9ICJsb3dlciIsIHRsLmNleCA9IDUpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSB0aGUgZGV2ZWxvcG1lbnQgdmFyaWFibGVzIChpbXApIHZhcmlhYmxlcyBhcmUgY29ycmVsYXRlZCB3aXRoIGVhY2ggb3RoZXIgYXMgd2UgbWlnaHQgZXhwZWN0LiBXZSBhbHNvIHNlZSB0aGF0IHRoZSByb2FkIGRlbnNpdHkgdmFyaWFibGVzIHNlZW0gdG8gYmUgY29ycmVsYXRlZCB3aXRoIGVhY2ggb3RoZXIsIGFuZCB0aGUgZW1pc3Npb24gdmFyaWFibGVzIHNlZW0gdG8gYmUgY29ycmVsYXRlZCB3aXRoIGVhY2ggb3RoZXIuIFdlIGNhbiB0YWtlIGEgY2xvc2VyIGxvb2sgIHVzaW5nIHRoZSBgZ2djb3JyKClgIGZ1bmN0aW9uIGFuZCB0aGUgYGdncGFpcnMoKWAgZnVuY3Rpb24gb2YgdGhlIGBHR2FsbHlgIHBhY2thZ2UuIFRvIHNlbGVjdCBvdXIgdmFyaWFibGVzIG9mIGludGVyZXN0IHdlIGNhbiB1c2UgdGhlIGBzZWxlY3QoKWAgZnVuY3Rpb24gd2l0aCB0aGUgYGNvbnRhaW5zKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGlkeXJgIHBhY2thZ2UuIAoKRmlyc3QgbGV0J3MgbG9vayBhdCB0aGUgaW1wL2RldmVsb3BtZW50IHZhcmlhYmxlcy4gCmBgYHtyLCBvdXQud2lkdGggPSAiNDAwcHgifQpzZWxlY3QocG0sIGNvbnRhaW5zKCJpbXAiKSkgJT4lCiAgZ2djb3JyKHBhbGV0dGUgPSAiUmRCdSIsIGxhYmVsID0gVFJVRSkKCnNlbGVjdChwbSwgY29udGFpbnMoImltcCIpKSAlPiUKICBnZ3BhaXJzKCkKICAKYGBgCgpJbmRlZWQsIHdlIGNhbiBzZWUgdGhhdCBpbXBfYTEwMDAgYW5kIGltcF9hNTAwIGFyZSBwZXJmZWN0bHkgY29ycmVsYXRlZCwgYXMgd2VsbCBhcyBpbXBfYTEwMDAwLCBpbXBfYTE1MDAwLgoKCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgcm9hZCBkZW5zaXR5IGRhdGE6CgpgYGB7ciwgZmlnLndlaWdodD0xMn0Kc2VsZWN0KHBtLCBjb250YWlucygicHJpIikpICU+JQogIGdnY29ycihwYWxldHRlID0gIlJkQnUiLCAgaGp1c3QgPSAuODUsIHNpemUgPSAzLAogICAgICAgbGF5b3V0LmV4cD0yLCBsYWJlbCA9IFRSVUUpCgpgYGAKCldlIGNhbiBzZWUgdGhhdCBtYW55IG9mIHRoZSByb2FkIGRlbnNpdHkgdmFyaWFibGVzIGFyZSBoaWdobHkgY29ycmVsYXRlZCB3aXRoIG9uZSBhbm90aGVyLCB3aGlsZSBvdGhlcnMgYXJlIGxlc3Mgc28uCgpGaW5hbGx5IGxldCdzIGxvb2sgYXQgdGhlIGVtaXNzaW9uIHZhcmlhYmxlcy4KCmBgYHtyfQpzZWxlY3QocG0sIGNvbnRhaW5zKCJuZWkiKSkgJT4lCiAgZ2djb3JyKHBhbGV0dGUgPSAiUmRCdSIsICBoanVzdCA9IC44NSwgc2l6ZSA9IDMsCiAgICAgICBsYXlvdXQuZXhwPTIsIGxhYmVsID0gVFJVRSkKCnNlbGVjdChwbSwgY29udGFpbnMoIm5laSIpKSAlPiUKICBnZ3BhaXJzKCkKYGBgCgpXZSB3b3VsZCBhbHNvIGV4cGVjdCB0aGUgcG9wdWxhdGlvbiBkZW5zaXR5IGRhdGEgbWlnaHQgY29ycmVsYXRlIHdpdGggc29tZSBvZiB0aGVzZSB2YXJpYWJsZXMuIExldCdzIHRha2UgYSBsb29rLgoKYGBge3J9CnBtICU+JQpzZWxlY3QobG9nX25laV8yMDA4X3BtMjVfc3VtXzEwMDAwLCBwb3BkZW5zX2NvdW50eSwgbG9nX3ByaV9sZW5ndGhfMTAwMDAsIGltcF9hMTAwMDApICU+JQogIGdnY29ycihwYWxldHRlID0gIlJkQnUiLCAgaGp1c3QgPSAuODUsIHNpemUgPSAzLAogICAgICAgbGF5b3V0LmV4cD0yLCBsYWJlbCA9IFRSVUUpCgpwbSAlPiUKc2VsZWN0KGxvZ19uZWlfMjAwOF9wbTI1X3N1bV8xMDAwMCwgcG9wZGVuc19jb3VudHksIGxvZ19wcmlfbGVuZ3RoXzEwMDAwLCBpbXBfYTEwMDAwLCBjb3VudHlfcG9wKSAlPiUKICBnZ3BhaXJzKCkKYGBgCgoKSW50ZXJlc3RpbmcsIHNvIHRoZXNlIHZhcmlhYmxlcyBkb24ndCBhcHBlYXIgdG8gYmUgaGlnaGx5IGNvcnJlbGF0ZWQsIHRoZXJlZm9yZSB3ZSBtaWdodCBuZWVkIHZhcmlhYmxlcyBmcm9tIGVhY2ggb2YgdGhlIGNhdGVnb3JpZXMgdG8gcHJlZGljdCBvdXIgbW9uaXRvciBQTX4yLjV+IHBvbGx1dGlvbiB2YWx1ZXMuCgpXZSBzZWVtIHRvIGhhdmUgc29tZSBwcmV0dHkgZXh0cmVtZSBwb3B1bGF0aW9uIHZhbHVlcyB0aG91Z2gsIHNvIGxldCdzIHNlZSB3aGF0IGhhcHBlbnMgd2hlbiB3ZSB0YWtlIHRoZSBsb2cgdmFsdWUuCgpgYGB7cn0KcG0gJT4lCiAgbXV0YXRlKGxvZ19wb3BkZW5zX2NvdW50eT0gbG9nKHBvcGRlbnNfY291bnR5KSkgJT4lCnNlbGVjdChsb2dfbmVpXzIwMDhfcG0yNV9zdW1fMTAwMDAsIGxvZ19wb3BkZW5zX2NvdW50eSwgbG9nX3ByaV9sZW5ndGhfMTAwMDAsIGltcF9hMTAwMDApICU+JQogIGdnY29ycihwYWxldHRlID0gIlJkQnUiLCAgaGp1c3QgPSAuODUsIHNpemUgPSAzLAogICAgICAgbGF5b3V0LmV4cD0yLCBsYWJlbCA9IFRSVUUpCgpwbSAlPiUKICBtdXRhdGUobG9nX3BvcGRlbnNfY291bnR5PSBsb2cocG9wZGVuc19jb3VudHkpKSAlPiUKICBtdXRhdGUobG9nX3BvcF9jb3VudHkgPSBsb2coY291bnR5X3BvcCkpICU+JQpzZWxlY3QobG9nX25laV8yMDA4X3BtMjVfc3VtXzEwMDAwLCBsb2dfcG9wZGVuc19jb3VudHksIGxvZ19wcmlfbGVuZ3RoXzEwMDAwLCBpbXBfYTEwMDAwLCBsb2dfcG9wX2NvdW50eSkgJT4lCiAgZ2dwYWlycygpCmBgYAoKSW5kZWVkIHRoaXMgaW5jcmVhc2VkIHRoZSBjb3JyZWxhdGlvbiwgYnV0IHZhcmlhYmxlcyBmcm9tIGVhY2ggb2YgdGhlc2UgY2F0ZWdvcmllcyBtYXkgc3RpbGwgcHJvdmUgdG8gYmUgdXNlZnVsIGZvciBwcmVkaWN0aW9uLgoKCgoKIyMgRGF0YSBBbmFseXNpcwoKTm93IHRoYXQgd2UgaGF2ZSBhIHNlbnNlIG9mIHdoYXQgb3VyIGRhdGEgaXMgbGlrZSB3ZSBjYW4gZ2V0IHN0YXJ0ZWQgd2l0aCBkYXRhIGFuYWx5c2lzLgoKIyMjIFRoZSBtYWNoaW5lIGxlYXJuaW5nIHByb2Nlc3MKClRoZXJlIGFyZSB0d28gbWFqb3IgdHlwZXMgb2YgbWFjaGluZSBsZWFybmluZzogIAoKMSkgVW5zdXBlcnZpc2VkICAKMikgU3VwZXJ2aXNlZCAgCgpVbnN1cGVydmlzZWQgbGVhcm5pbmcgaXMgdXNlZCB0byBsZWFybiBhYm91dCB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhIHdpdGhvdXQga25vd2luZyBtdWNoIGFib3V0IHRoZSBkYXRhLiBXZSBsZXQgdGhlIGRhdGEgcmV2ZWFsIHByb3BlcnRpZXMgYWJvdXQgaXRzZWxmLiBFeGFtcGxlcyBpbmNsdWRlIGNsdXN0ZXJpbmcgdGhlIGRhdGEgaW50byBncm91cHMgb3IgcmVkdWNpbmcgdGhlIGRpbWVuc2lvbmFsaXR5IG9mIHRoZSBkYXRhIHVzaW5nIG1ldGhvZHMgbGlrZSBbcHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpc10oaHR0cHM6Ly9tZWRpdW0uY29tL0BzYXZhc3RhbWlya28vcGNhLWEtbGluZWFyLXRyYW5zZm9ybWF0aW9uLWY4YWFjZDRlYjAwNyl7dGFyZ2V0PSJfYmxhbmsifSAod2hpY2ggd2Ugd2lsbCBkZXNjcmliZSBpbiBtb3JlIGRldGFpbCBsYXRlcikgdG8gY2FwdHVyZSBwYXR0ZXJucyBvZiB2YXJpYW5jZSB3aXRoaW4gdGhlIGRhdGEuCgpgYGB7ciwgb3V0LndpZHRoID0gIjgwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly9taXJvLm1lZGl1bS5jb20vbWF4LzE0MDAvMSpsaGtDT29kQ01aMC1TU3ppRURwd3BBLnBuZyIpCmBgYAoKIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL3N1cGVydmlzZWQtdnMtdW5zdXBlcnZpc2VkLWxlYXJuaW5nLTE0ZjY4ZTMyZWE4ZClde3RhcmdldD0iX2JsYW5rIn0KCkluIGNvbnRyYXN0LCBpbiBzdXBlcnZpc2VkIGxlYXJuaW5nIHdlIGhhdmUgc29tZSBrbm93bGVkZ2UgYWJvdXQgdGhlIGRhdGEgdGhhdCB3ZSB3YW50IHRvIHVzZSB0byBjcmVhdGUgYSBtb2RlbCB0byBiZSBhYmxlIHRvIGdlbmVyYWxpemUgYWJvdXQgb3RoZXIgc2ltaWxhciBkYXRhLgoKVGhlcmUgYXJlIHR3byBkaXN0aW5jdCBnb2FscyBvZiBzdXBlcnZpc2VkIG1hY2hpbmUgbGVhcm5pbmc6ICAKCjEpIFByZWRpY3Rpb24gIAoyKSBDbGFzc2lmaWNhdGlvbiAgCgpgYGB7ciwgb3V0LndpZHRoID0gIjgwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly9taXJvLm1lZGl1bS5jb20vbWF4LzE0MDAvMSpBU1lwRmZEaDdYbnJlVS15Z3FYb253LnBuZyIpCmBgYAoKIyMjIyBbW3NvdXJjZV0oaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL3N1cGVydmlzZWQtdnMtdW5zdXBlcnZpc2VkLWxlYXJuaW5nLTE0ZjY4ZTMyZWE4ZClde3RhcmdldD0iX2JsYW5rIn0KCldlIHdpbGwgYmUgcGVyZm9ybWluZyBhIHByZWRpY3Rpb24gYW5hbHlzaXMgKHdoaWNoIGlzIGFsc28gcmVmZXJyZWQgdG8gYXMgcmVncmVzc2lvbiksIHdoaWNoIGFpbXMgdG8gcHJlZGljdCAqKmNvbnRpbnVvdXMgb3V0Y29tZSoqIHZhcmlhYmxlcyBnaXZlbiBhIG51bWJlciBvZiBwcmVkaWN0b3JzL2V4cGxhbmF0b3J5IHZhcmlhYmxlcy9mZWF0dXJlcy9wYXJhbWV0ZXJzLCBhcyB3ZSBoYXZlIGFscmVhZHkgZGVzY3JpYmVkLgoKQ2xhc3NpZmljYXRpb24gb24gdGhlIG90aGVyIGhhbmQgYWltcyB0byBkaXNjZXJuIG9yIHByZWRpY3QgZ3JvdXAgaWRlbnRpdHkgZm9yIGEgKipjYXRlZ29yaWNhbCBvdXRjb21lKiogYmFzZWQgb24gYSBudW1iZXIgb2YgcHJlZGljdG9ycy9leHBsYW5hdG9yeSB2YXJpYWJsZXMvZmVhdHVyZXMvcGFyYW1ldGVycy4KClRoZSBvdmVyYWxsIHByb2Nlc3MgaXMgdGhlIHNhbWUgaW4gZWl0aGVyIGNhc2UgYW5kIGludm9sdmVzIHRoZSBmb2xsb3dpbmcgc3RlcHMgKHdoaWNoIHdpbGwgZWFjaCBiZSBleHBsYWluZWQgaW4gZGV0YWlsKTogCgoxKSBEYXRhIGV4cGxvcmF0aW9uICAKCldlIGhhdmUgYWxyZWFkeSBwZXJmb3JtZWQgdGhpcyBzdGVwIHRvIGdldCBhIHNlbnNlIG9mIHRoZSBkYXRhLiBJdCBpcyBpbXBvcnRhbnQgdG8ga25vdyBpZiB3ZSBoYXZlIGBOQWAgdmFsdWVzLCB0byB1bmRlcnN0YW5kIHRoZSBjbGFzcyBvZiB2YXJpYWJsZXMsIGFuZCBpZiB0byBkZXRlcm1pbmUgaWYgdGhlcmUgYXJlIGFueSByZWR1bmRhbnQgdmFyaWFibGVzIHRoYXQgbWlnaHQgbmVlZCB0byByZW1vdmVkLgoKMikgRGF0YSBzcGxpdHRpbmcgCgpUaGUgZGF0YSBuZWVkcyB0byBiZSBzcGxpdCBpbnRvIHR3byBwaWVjZXM6IGEgdHJhaW5pbmcgc2V0IGFuZCBhIHRlc3Rpbmcgc2V0LiBUaGUgdHJhaW5pbmcgc2V0IHdpbGwgYmUgdXNlZCB0byBvcHRpbWl6ZSB0aGUgbW9kZWwsIHdoaWxlIHRoZSB0ZXN0aW5nIHNldCB3aWxsIGJlIHVzZWQgdG8gZXZhbHVhdGUgbW9kZWwgcGVyZm9ybWFuY2UuIAoKMykgVmFyaWFibGUgYXNzaWdubWVudCBhbmQgcHJlcHJvY2Vzc2luZyAgCgpCb3RoIHRoZSB0cmFpbmluZyBhbmQgdGVzdGluZyBkYXRhIG5lZWRzIHRvIGJlIHByb2Nlc3NlZCBzbyB0aGF0IHRoZSBkYXRhIGlzIGNvbXBhdGlibGUgYW5kIG9wdGltaXplZCB0byBiZSB1c2VkIHdpdGggdGhlIG1vZGVsLiBUaGlzIGludm9sdmVzIGFzc2lnbmluZyB2YXJpYWJsZXMgdG8gc3BlY2lmaWMgcm9sZXMgd2l0aGluIHRoZSBtb2RlbCBhbmQgcHJlcHJvY2Vzc2luZyBsaWtlIHNjYWxpbmcgdmFyaWFibGVzIGFuZCByZW1vdmluZyByZWR1bmRhbnQgdmFyaWFibGVzLiBUaGlzIHByb2Nlc3MgaXMgYWxzbyBjYWxsZWQgZmVhdHVyZSBlbmdpbmVlcmluZy4KCjQpIE1vZGVsIHNwZWNpZmljYXRpb24sIGZpdHRpbmcsIHR1bmluZyBhbmQgcGVyZm9ybWFuY2UgZXZhbHVhdGlvbiB1c2luZyB0aGUgdHJhaW5pbmcgZGF0YQoKVGhlIG1vZGVsIG5lZWRzIHRvIGZpcnN0IGJlIGZpdCB0byB0aGUgdHJhaW5pbmcgZGF0YS4gRmlyc3QgdGhlIG1ldGhvZCBvciBhbGdvcml0aG0gaW4gd2hpY2ggdGhlIG1vZGVsIHdpbGwgYmUgZml0IGlzIHNwZWNpZmllZCAocmVncmVzc2lvbiwgcmFuZG9tIGZvcmVzdCBldGMuKS4gIFRoZW4gaW4gYm90aCBjbGFzc2lmaWNhdGlvbiBhbmQgcHJlZGljdGlvbiwgdGhlIG1vZGVsIGlzIGZpdCB0byB0aGUgdHJhaW5pbmcgZGF0YSBhbmQgdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBhcmUgdXNlZCB0byBlc3RpbWF0ZSBudW1lcmljIHZhbHVlcyAoaW4gdGhlIGNhc2Ugb2YgcHJlZGljdGlvbikgb3IgY2F0ZWdvcmljYWwgdmFsdWVzIChpbiB0aGUgY2FzZSBvZiBjbGFzc2lmaWNhdGlvbikgb2YgdGhlIG91dGNvbWUgdmFyaWFibGUgb2YgaW50ZXJlc3QuIElmIHRoZSBtb2RlbCBmaXRzIHdlbGwgdGhhbiB0aGVzZSBlc3RpbWF0ZWQgdmFsdWVzIHdpbGwgYmUgdmVyeSBzaW1pbGFyIHRvIHRoZSB0cnVlIG91dGNvbWUgdmFyaWFibGUgdmFsdWVzLiBJZiB0aGUgbW9kZWwgZG9lcyBub3QgZml0IHdlbGwsIHRoYW4gdGhlc2UgZXN0aW1hdGVzIHdpbGwgYmUgbW9yZSBkaXNpbWlsYXIgZnJvbSB0aGUgdHJ1ZSBvdXRjb21lIHZhcmlhYmxlLiBJbiB0aGlzIGNhc2UsIGFzcGVjdHMgYWJvdXQgdGhlIG1vZGVsIG1heSBuZWVkIHRvIGJlIG1vZGlmaWVkIHRvIGltcHJvdmUgdGhlIHNpbWlsYXJpdHkgb2YgdGhlIGVzdGltYXRlcyB3aXRoIHRoYXQgb2YgdGhlIHRydWUgb3V0Y29tZSB2YWx1ZXMuIE9uZSB3YXkgdG8gb3B0aW1pemUgbW9kZWwgcGVyZm9ybWFuY2UgaXMgYSBwcm9jZXNzIGNhbGxlZCB0dW5pbmcgaW4gd2hpY2ggZGlmZmVyZW50IG1vZGVsIFtoeXBlci1wYXJhbWV0ZXJdKGh0dHBzOi8vd3d3LmRhdGFjYW1wLmNvbS9jb21tdW5pdHkvdHV0b3JpYWxzL3BhcmFtZXRlci1vcHRpbWl6YXRpb24tbWFjaGluZS1sZWFybmluZy1tb2RlbHMpe3RhcmdldD0iX2JsYW5rIn0gb3B0aW9ucyBhcmUgdGVzdGVkIHRvIGRldGVybWluZSB0aGUgYmVzdCBvcHRpb24gZm9yIG1vZGVsIHBlcmZvcm1hbmNlLgoKNSkgT3ZlcmFsbCBtb2RlbCBwZXJmb3JtYW5jZSBldmFsdWF0aW9uCgpNb2RlbCBwZXJmb3JtYW5jZSBpcyBhc3Nlc3NlZCBhcyB0aGUgc2ltaWxhcml0eSBiZXR3ZWVuIHRoZSBlc3RpbWF0ZXMgb2YgdGhlIG91dGNvbWUgdmFyaWFibGUgcHJvZHVjZWQgYnkgdGhlIG1vZGVsIGFuZCB0aGUgdHJ1ZSBvdXRjb21lIHZhcmlhYmxlIHZhbHVlcy4gVGhpcyBpcyBkb25lIHR5cGljYWxseSBhcyBhbiBpdGVyYXRpdmUgcHJvY2VzcyB3aXRoIHRoZSB0cmFpbmluZyBkYXRhIGFsb25nIHNpZGUgbW9kaWZpY2F0aW9uIG9mIHRoZSBtb2RlbCB1bnRpbCB0aGUgcGVyZm9ybWFuY2UgdXNpbmcgdGhlIHRyYWluaW5nIGRhdGEgaXMgc2F0aXNmYWN0b3J5LiBBdCB0aGlzIHBvaW50LCB0aGUgZmluYWwgbW9kZWwgcGVyZm9ybWFuY2UgaXMgYXNzZXNzZWQgdXNpbmcgdGhlIHRlc3RpbmcgZGF0YS4gVGhpcyB0aGVuIGdpdmVzIGFuIGVzdGltYXRlIGFib3V0IGhvdyB3ZWxsIHRoZSBtb2RlbCB3aWxsIHByZWRpY3Qgb3IgY2xhc3NpZnkgdGhlIG91dGNvbWUgdmFyaWFibGUgb2YgaW50ZXJlc3Qgd2l0aCBuZXcgaW5kZXBlbmRlbnQgZGF0YS4gSWRlYWxseSBvbmUgd291bGQgYWxzbyBwZXJmb3JtIGFuIGV2YWx1YXRpb24gd2l0aCBpbmRlcGVuZGVudCBkYXRhIHRvIHByb3ZpZGUgYSBzZW5zZSBvZiBob3cgZ2VuZXJhbGl6YWJsZSB0aGUgbW9kZWwgaXMgdG8gb3RoZXIgZGF0YSBzb3VyY2VzLgoKIyMjIFRoZSB0aWR5bW9kZWxzIGVjb3N5c3RlbQoKVG8gcGVyZm9ybSBvdXIgYW5hbHlzaXMgd2Ugd2lsbCBiZSB1c2luZyB0aGUgYHRpZHltb2RlbHNgIHN1aXRlIG9mIHBhY2thZ2VzLiBZb3UgbWF5IGJlIGZhbWlsaWFyIHdpdGggdGhlIG9sZGVyIHBhY2thZ2VzIGBjYXJldGAgb3IgYG1scmAgd2hpY2ggYXJlIGFsc28gZm9yIG1hY2hpbmUgbGVhcm5pbmcgYW5kIG1vZGVsaW5nIGJ1dCBhcmUgbm90IGEgcGFydCBvZiB0aGUgYHRpZHl2ZXJzZWAuIFtNYXggS3Vobl0oaHR0cHM6Ly9yZXNvdXJjZXMucnN0dWRpby5jb20vYXV0aG9ycy9tYXgta3Vobil7dGFyZ2V0PSJfYmxhbmsifSBkZXNjcmliZXMgYHRpZHltb2RlbHNgIGxpa2UgdGhpczoKCj4gIk90aGVyIHBhY2thZ2VzLCBzdWNoIGFzIGNhcmV0IGFuZCBtbHIsIGhlbHAgdG8gc29sdmUgdGhlIFIgbW9kZWwgQVBJIGlzc3VlLiBUaGVzZSBwYWNrYWdlcyBkbyBhIGxvdCBvZiBvdGhlciB0aGluZ3MgdG9vOiBwcmVwcm9jZXNzaW5nLCBtb2RlbCB0dW5pbmcsIHJlc2FtcGxpbmcsIGZlYXR1cmUgc2VsZWN0aW9uLCBlbnNlbWJsaW5nLCBhbmQgc28gb24uIEluIHRoZSB0aWR5dmVyc2UsIHdlIHN0cml2ZSB0byBtYWtlIG91ciBwYWNrYWdlcyBtb2R1bGFyIGFuZCBwYXJzbmlwIGlzIGRlc2lnbmVkIG9ubHkgdG8gc29sdmUgdGhlIGludGVyZmFjZSBpc3N1ZS4gSXQgaXMgbm90IGRlc2lnbmVkIHRvIGJlIGEgZHJvcC1pbiByZXBsYWNlbWVudCBmb3IgY2FyZXQuClRoZSB0aWR5bW9kZWxzIHBhY2thZ2UgY29sbGVjdGlvbiwgd2hpY2ggaW5jbHVkZXMgcGFyc25pcCwgaGFzIG90aGVyIHBhY2thZ2VzIGZvciBtYW55IG9mIHRoZXNlIHRhc2tzLCBhbmQgdGhleSBhcmUgZGVzaWduZWQgdG8gd29yayB0b2dldGhlci4gV2UgYXJlIHdvcmtpbmcgdG93YXJkcyBoaWdoZXItbGV2ZWwgQVBJcyB0aGF0IGNhbiByZXBsaWNhdGUgYW5kIGV4dGVuZCB3aGF0IHRoZSBjdXJyZW50IG1vZGVsIHBhY2thZ2VzIGNhbiBkby4iCgpUaGVyZSBhcmUgbWFueSBwYWNrYWdlcyBpbiB0aGUgdGlkeW1vZGVscyBlY29zeXN0ZW0gd2hpY2ggYXNzaXN0IHdpdGggdGhlIHZhcmlvdXMgc3RlcHMgb2YgdGhlIG1hY2hpbmUgbGVhcm5pbmcgcHJvY2VzczoKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwic2ltcGxldGlkeW1vZGVscy5wbmciKSkKYGBgCgoKVGhpcyBpcyBhIGRlcGljdGlvbiBvZiBob3cgdGhlc2UgdG9vbHMgaGVscCBwZXJmb3JtIHRoZSBvdmVyYWxsIG1hY2hpbmUgbGVhcm5pbmcgcHJvY2VzczoKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjgwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwiTWFjaGluZUxlYXJuaW5nLnBuZyIpKQpgYGAKCiMjIyBUaGUgbWFqb3IgYmVuZWZpdHMgb2YgdGlkeW1vZGVscyAgCgoxKSBTdGFuZGFyZGl6ZWQgd29ya2Zsb3cvZm9ybWF0L25vdGF0aW9uIGFjcm9zcyBkaWZmZXJlbnQgdHlwZXMgb2YgYWxnb3JpdGhtcyAgCgpEaWZmZXJlbnQgbm90YXRpb25zIGFyZSByZXF1aXJlZCBmb3IgZGlmZmVyZW50IGFsZ29yaXRobXMgYXMgdGhlIGFsZ29yaXRobXMgaGF2ZSBiZWVuIGRldmVsb3BlZCBieSBtYW55IGRpZmZlcmVudCBwZW9wbGUuIFRoaXMgd291bGQgcmVxdWlyZSB0aGUgcGFpbnN0YWtpbmcgcHJvY2VzcyBvZiByZWZvcm1hdHRpbmcgdGhlIGRhdGEgdG8gYmUgY29tcGF0aWJsZSB3aXRoIGVhY2ggYWxnb3JpdGhtIGlmIG11bHRpcGxlIGFsZ29yaXRobXMgd2VyZSB0ZXN0ZWQuCgoyKSBDYW4gZWFzaWx5IG1vZGlmeSBwcmVwcm9jZXNzaW5nLCBhbGdvcml0aG0gY2hvaWNlLCBhbmQgaHlwZXItcGFyYW1ldGVyIHR1bmluZyBtYWtpbmcgb3B0aW1pemF0aW9uIGVhc3kgIAoKTW9kaWZ5aW5nIGEgcGllY2Ugb2YgdGhlIG92ZXJhbGwgcHJvY2VzcyBpcyBub3cgbXVjaCBlYXNpZXIgdGhhbiBiZWZvcmUgYmVjYXVzZSBtYW55IG9mIHRoZSBzdGVwcyBhcmUgc3BlY2lmaWVkIHVzaW5nIHRoZSB0aWR5bW9kZWwgcGFja2FnZXMgaW4gYSBjb252ZW5pZW50IG1hbm5lci4gVGh1cyB0aGUgZW50aXJlIHByb2Nlc3MgY2FuIGJlIHJlcnVuIGFmdGVyIGEgc2ltcGxlIGNoYW5nZSB0byBwcmVwcm9jZXNzaW5nIHdpdGhvdXQgbXVjaCBkaWZmaWN1bHR5LgoKIyMjIFNwbGl0dGluZyB0aGUgRGF0YQoKVGhlIGZpcnN0IHN0ZXAgYWZ0ZXIgZGF0YSBleHBsb3JhdGlvbiBpbiBtYWNoaW5lIGxlYXJuaW5nIGFuYWx5c2lzIGlzIHRvIFtzcGxpdCB0aGUgZGF0YV0oaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL3RyYWluLXZhbGlkYXRpb24tYW5kLXRlc3Qtc2V0cy03MmNiNDBjYmE5ZTcpe3RhcmdldD0iX2JsYW5rIn0gaW50byAqKnRyYWluaW5nKiogYW5kICoqdGVzdGluZyoqIGRhdGFzZXRzLiAKClRoZSB0cmFpbmluZyBkYXRhc2V0IHdpbGwgYmUgdXNlZCB0byBidWlsZCBhbmQgdHVuZSBvdXIgbW9kZWwuIFRoaXMgaXMgdGhlIGRhdGEgdGhhdCB0aGUgbW9kZWwgImxlYXJucyIgb24uCgpUaGUgdGVzdGluZyBzZXQgd2lsbCBiZSB1c2VkIHRvIGV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBvdXIgbW9kZWwgaW4gYSBtb3JlIGdlbmVyYWxpemFibGUgd2F5LiBXaGF0IGRvIHdlIG1lYW4gYnkgImdlbmVyYWxpemFibGUiPwoKUmVtZW1iZXIgdGhhdCBvdXIgbWFpbiBnb2FsIGlzIHRvIHVzZSBvdXIgbW9kZWwgdG8gYmUgYWJsZSB0byBwcmVkaWN0IGFpciBwb2xsdXRpb24gbGV2ZWxzIGluIGFyZWFzIHdoZXJlIHRoZXJlIGFyZSBubyBncmF2aW1ldHJpYyBtb25pdG9ycy4gVGhlcmVmb3JlLCBpZiBvdXIgbW9kZWwgaXMgc3VwZXIgZ29vZCBhdCBwcmVkaWN0aW5nIGFpciBwb2xsdXRpb24gd2l0aCB0aGUgZGF0YSB0aGF0IHdlIHVzZSB0byBidWlsZCBpdCwgaXQgbWlnaHQgbm90IGRvIHRoZSBiZXN0IGpvYiBmb3IgdGhlIGFyZWFzIHdoZXJlIHRoZXJlIGFyZSBmZXcgdG8gbm8gbW9uaXRvcnMuIFRoaXMgd291bGQgY2F1c2UgdXMgdG8gaGF2ZSByZWFsbHkgZ29vZCBwcmVkaWN0aW9uIGFjY3VyYWN5IGFuZCB3ZSBtaWdodCBhc3N1bWUgdGhhdCB3ZSB3ZXJlIGdvaW5nIHRvIGRvIGEgZ29vZCBqb2IgZXN0aW1hdGluZyBhaXIgcG9sbHV0aW9uIGFueSB0aW1lIHdlIHVzZSBvdXIgbW9kZWwsIGJ1dCBpbiBmYWN0IHRoaXMgd291bGQgbGlrZWx5IG5vdCBiZSB0aGUgY2FzZS4gVGhpcyBzaXR1YXRpb24gaXMgd2hhdCB3ZSBjYWxsICoqW292ZXJmaXR0aW5nXShodHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vdHJhaW4tdGVzdC1zcGxpdC1hbmQtY3Jvc3MtdmFsaWRhdGlvbi1pbi1weXRob24tODBiNjFiZWNhNGI2KXt0YXJnZXQ9Il9ibGFuayJ9ICoqLgoKT3ZlcmZpdHRpbmcgaGFwcGVucyB3aGVuIHdlIGVuZCB1cCBtb2RlbGluZyBub3Qgb25seSB0aGUgbWFqb3IgcmVsYXRpb25zaGlwcyBpbiBvdXIgZGF0YSBidXQgYWxzbyB0aGUgbm9pc2Ugd2l0aGluIG91ciBkYXRhLiAKCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vbWlyby5tZWRpdW0uY29tL21heC8xMTEwLzEqdEJFclhZVnZUdzJqU1VZSzd0aFUyQS5wbmciKQpgYGAKCiMjIyMjIFtbc291cmNlXShodHRwczovL21pcm8ubWVkaXVtLmNvbS9tYXgvMTExMC8xKnRCRXJYWVZ2VHcyalNVWUs3dGhVMkEucG5nKV17dGFyZ2V0PSJfYmxhbmsifQoKSWYgd2UgZ2V0IGZhaXJseSBnb29kIHByZWRpY3Rpb24gd2l0aCBvdXIgdGVzdGluZyBzZXQgdGhlbiB3ZSB3aWxsIGtub3cgdGhhdCBvdXIgbW9kZWwgY2FuIGJlIGFwcGxpZWQgdG8gb3RoZXIgZGF0YSBhbmQgd2lsbCBwZXJmb3JtIGZhaXJseSB3ZWxsLiBXZSB3aWxsIGRpc2N1c3MgdGhpcyBtb3JlIGxhdGVyLgoKV2Ugd2lsbCBub3QgdG91Y2ggdGhlIHRlc3Rpbmcgc2V0IHVudGlsIHdlIGhhdmUgY29tcGxldGVkIG9wdGltaXppbmcgb3VyIG1vZGVsIHdpdGggdGhlIHRyYWluaW5nIHNldC4gVGhpcyB3aWxsIGFsbG93IHVzIHRvIGhhdmUgYSBsZXNzIGJpYXNlZCBldmFsdWF0aW9uIG9mIGhvdyB3ZWxsIG91ciBtb2RlbCBjYW4gZG8gd2l0aCBvdGhlciBkYXRhIGJlc2lkZXMgdGhlIGRhdGEgdXNlZCBpbiB0aGUgdHJhaW5pbmcgc2V0IHRvIGJ1aWxkIHRoZSBtb2RlbC4gSWRlYWxseSB5b3Ugd291bGQgYWxzbyB3YW50IGEgY29tcGxldGVseSBpbmRlcGVuZGVudCBkYXRhc2V0IHRvIGZ1cnRoZXIgdGVzdCB0aGUgcGVyZm9ybWFuY2Ugb2YgeW91ciBtb2RlbC4KCltIZXJlXShodHRwczovL21hY2hpbmVsZWFybmluZ21hc3RlcnkuY29tL2RpZmZlcmVuY2UtdGVzdC12YWxpZGF0aW9uLWRhdGFzZXRzLyl7dGFyZ2V0PSJfYmxhbmsifSBpcyBhIGdyZWF0IGRlc2NyaXB0aW9uIG9mIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRlc3RpbmcgYW5kIHRyYWluaW5nIGRhdGFzZXRzLgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNDAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJzcGxpdC5wbmciKSkKYGBgCldlIHdpbGwgdXNlIHRoZSBgcnNhbXBsZWAgcGFja2FnZSB0byBwZXJmb3JtIHRoaXMgc3RlcC4KClRoZWBpbml0aWFsX3NwbGl0KClgIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBzcGVjaWZ5IGhvdyB3ZSB3YW50IHRvIHNwbGl0IG91ciBkYXRhLiBUeXBpY2FsbHkgZGF0YSBpcyBzcGxpdCBpbnRvIDMvNCBmb3IgdHJhaW5pbmcgYW5kIDEvNCBmb3IgdGVzdGluZy5UaGlzIGlzIHRoZSBkZWZhdWx0IHByb3BvcnRpb24gYW5kIGRvZXMgbm90IG5lZWQgdG8gYmUgc3BlY2lmaWVkLiBIb3dldmVyIHlvdSBjYW4gY2hhbmdlIHRoZSBwcm9wb3J0aW9uIHVzaW5nIHRoZSBgcHJvcGAgYXJndW1lbnQsIHdoaWNoIHdlIHdpbGwgZG8gdGhhdCBoZXJlIGZvciBpbGx1c3RyYXRpdmUgcHVycG9zZXMuIFlvdSBjYW4gYWxzbyBzcGVjaWZ5IGEgdmFyaWFibGUgdG8gc3RyYXRpZnkgYnkgd2l0aCB0aGUgYHN0cmF0YWAgYXJndW1lbnQuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSBoYXZlIGltYmFsYW5jZWQgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFuZCB5b3Ugd291bGQgbGlrZSB0byBpbnRlbnRpb25hbGx5IG1ha2Ugc3VyZSB0aGF0IHRoZXJlIGFyZSBzaW1pbGFyIG51bWJlciBvZiBzYW1wbGVzIG9mIHRoZSByYXJlciBjYXRlZ29yaWVzIGluIGJvdGggdGhlIHRlc3RpbmcgYW5kIHRyYWluaW5nIHNldHMuIE90aGVyd2lzZSB0aGUgc3BsaXQgaXMgcGVyZm9ybWVkIHJhbmRvbWx5LiAKCj4gVGhlIHN0cmF0YSBhcmd1bWVudCBjYXVzZXMgdGhlIHJhbmRvbSBzYW1wbGluZyB0byBiZSBjb25kdWN0ZWQgd2l0aGluIHRoZSBzdHJhdGlmaWNhdGlvbiB2YXJpYWJsZS4gVGhlIGNhbiBoZWxwIGVuc3VyZSB0aGF0IHRoZSBudW1iZXIgb2YgZGF0YSBwb2ludHMgaW4gdGhlIHRyYWluaW5nIGRhdGEgaXMgZXF1aXZhbGVudCB0byB0aGUgcHJvcG9ydGlvbnMgaW4gdGhlIG9yaWdpbmFsIGRhdGEgc2V0LgoKSW4gdGhlIGNhc2Ugd2l0aCBvdXIgZGF0YXNldCwgcGVyaGFwcyB3ZSB3b3VsZCBsaWtlIG91ciB0cmFpbmluZyBzZXQgdG8gaGF2ZSBzaW1pbGFyIHByb3BvcnRpb25zIG9mIG1vbml0b3JzIGZyb20gZWFjaCBvZiB0aGUgc3RhdGVzIGFzIGluIHRoZSBpbml0aWFsIGRhdGEuIFRoaXMgbWlnaHQgYmUgdXNlZnVsIGlmIHdlIHdhbnQgb3VyIG1vZGVsIHRvIGJlIGdlbmVyYWxpemFibGUgYWNyb3NzIGFsbCBvZiB0aGUgc3RhdGVzLgoKV2UgY2FuIHNlZSB0aGF0IGluZGVlZCB0aGVyZSBhcmUgZGlmZmVyZW50IHByb3BvcnRpb25zIG9mIG1vbml0b3JzIGluIGVhY2ggc3RhdGUgYnkgdXNpbmcgdGhlIGBjb3VudCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRweXJgIHBhY2thZ2UuIAoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpjb3VudChwbSwgc3RhdGUpICU+JQogIHByaW50KG4gPSAxZTMpCmBgYAojIyMjCgpJZiBvdXIgZGF0YXNldCB3ZXJlIGxhcmdlIGVub3VnaCBpdCBtaWdodCBiZSBuaWNlIHRoZW4gdG8gc3RyYXRpZnkgYnkgc3RhdGUsIGJ1dCBvdXIgZGF0YSBpcyB1bmZvcnR1bmF0ZWx5IG5vdCBsYXJnZSBlbm91Z2guIFdlIHdpbGwgc2hvdyBob3cgb25lIHdvdWxkIGRvIHRoaXMgdGhvdWdoIGZvciBpbGx1c3RyYXRpdmUgcHVycG9zZXMuIFRoaXMgb3B0aW9uIGlzIG9mdGVuIG1vcmUgaW1wb3J0YW50IGZvciBjbGFzc2lmaWNhdGlvbiBhcHBsaWNhdGlvbnMgb2YgbWFjaGluZSBsZWFybmluZyB0aGFuIGl0IGlzIGZvciBwcmVkaWN0aW9uLgoKU2luY2UgdGhlIHNwbGl0IGlzIHBlcmZvcm1lZCByYW5kb21seSwgaXQgaXMgYSBnb29kIGlkZWEgdG8gdXNlIHRoZSBgc2V0LnNlZWQoKWAgYmFzZSBmdW5jdGlvbiB0byBlbnN1cmUgdGhhdCBpZiB5b3VyIHJlcnVuIHlvdXIgY29kZSB0aGF0IHlvdXIgc3BsaXQgd2lsbCBiZSB0aGUgc2FtZSBuZXh0IHRpbWUuIFdlIGNhbiBzZWUgdGhlIG51bWJlciBvZiBtb25pdG9ycyBpbiBvdXIgdHJhaW5pbmcsIHRlc3RpbmcsIGFuZCBvcmlnaW5hbCBkYXRhIGJ5IHR5cGluZyBpbiB0aGUgbmFtZSBvZiBvdXIgc3BsaXQgb2JqZWN0LiBUaGUgcmVzdWx0IHdpbGwgbG9vayBsaWtlIHRoaXM6Cjx0cmFpbmluZyBkYXRhIHNhbXBsZSBudW1iZXIsIHRlc3RpbmcgZGF0YSBzYW1wbGUgbnVtYmVyLCBvcmlnaW5hbCBzYW1wbGUgbnVtYmVyPiAKCmBgYHtyfQpzZXQuc2VlZCgxMjM0KQpwbV9zcGxpdCA8LXJzYW1wbGU6OmluaXRpYWxfc3BsaXQoZGF0YSA9IHBtLCBwcm9wID0gMi8zKQpwbV9zcGxpdAoKIyBJZiBzdHJhdGlmeWluZzoKIyBwbV9zcGxpdF9zdHJhdGEgPC1yc2FtcGxlOjppbml0aWFsX3NwbGl0KGRhdGEgPSBwbSwgcHJvcCA9IDIvMywgc3RyYXRhID0gInN0YXRlIikKCmBgYAoKSW1wb3J0YW50bHkgdGhlIGBpbml0aWFsX3NwbGl0YCBmdW5jdGlvbiBvbmx5IGRldGVybWluZXMgd2hhdCByb3dzIG9mIG91ciBwbSBkYXRhIGZyYW1lIHNob3VsZCBiZSBhc3NpZ25lZCBmb3IgdHJhaW5pbmcgb3IgdGVzdGluZywgaXQgZG9lcyBub3QgYWN0dWFsbHkgc3BsaXQgdGhlIGRhdGEuIAoKVG8gZXh0cmFjdCB0aGUgdGVzdGluZyBhbmQgdHJhaW5pbmcgZGF0YSB3ZSBjYW4gdXNlIHRoZSBgdHJhaW5pbmcoKWAgYW5kIGB0ZXN0aW5nKClgIGZ1bmN0aW9ucyBhbHNvIG9mIHRoZSBgcnNhbXBsZWAgcGFja2FnZS4KCiMjIyMgey5zY3JvbGxhYmxlIH0KYGBge3J9CiB0cmFpbl9wbSA8LXJzYW1wbGU6OnRyYWluaW5nKHBtX3NwbGl0KQogdGVzdF9wbSA8LXJzYW1wbGU6OnRlc3RpbmcocG1fc3BsaXQpCiAKIyBTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpjb3VudCh0cmFpbl9wbSwgc3RhdGUpCmNvdW50KHRlc3RfcG0sIHN0YXRlKQpgYGAKIyMjIwoKCgojIyMgVmFyaWFibGUgUm9sZSBBc3NpZ25tZW50IGFuZCBQcmVwcm9jZXNzaW5nCgpJbiB0aWR5bW9kZWxzIHdlIHdpbGwgY3JlYXRlIGEgcmVjaXBlLCB3aGljaCBpcyBhIHN0YW5kYXJkaXplZCBmb3JtYXQgZm9yIGEgc2VxdWVuY2Ugb2Ygc3RlcHMgZm9yIHByb2Nlc3NpbmcgdGhlIGRhdGEuCgpUaGlzIGNhbiBiZSB2ZXJ5IHVzZWZ1bCBiZWNhdXNlIGl0IG1ha2VzIHRlc3Rpbmcgb3V0IGRpZmZlcmVudCBwcmVwcm9jZXNzaW5nIHN0ZXBzIG9yIGRpZmZlcmVudCBhbGdvcml0aG1zIHdpdGggdGhlIHNhbWUgcHJlcHJvY2Vzc2luZyB2ZXJ5IGVhc3kgYW5kIHJlcHJvZHVjaWJsZS4KCioqQ3JlYXRpbmcgYSByZWNpcGUgc3BlY2lmaWVzIGhvdyBhIGRhdGEgZnJhbWUgb2YgcHJlZGljdG9ycyBzaG91bGQgYmUgY3JlYXRlZCAgLSBpdCBzcGVjaWZpZXMgd2hhdCAgdmFyaWFibGVzIHRvIGJlIHVzZWQgIGFuZCB0aGUgIHByZXByb2Nlc3Npbmcgc3RlcHMgIGJ1dCBpdCBkb2VzIG5vdCBleGVjdXRlIHRoZXNlIHN0ZXBzIG9yIGNyZWF0ZSB0aGUgZGF0YSBmcmFtZSBvZiBwcmVkaWN0b3JzLioqCgojIyMjIExpc3QgdGhlIGluZ3JlZGllbnRzIC8gc3BlY2lmeSB0aGUgdmFyaWFibGVzIHdpdGggdGhlIGByZWNpcGUoKWAgZnVuY3Rpb24KClRoZSBmaXJzdCB0aGluZyB0byBkbyB0byBjcmVhdGUgYSByZWNpcGUgaXMgdG8gc3BlY2lmeSB3aGljaCB2YXJpYWJsZXMgd2Ugd2lsbCBiZSB1c2luZyBhcyBvdXIgb3V0Y29tZSBhbmQgcHJlZGljdG9ycyB1c2luZyB0aGUgYHJlY2lwZSgpYCBmdW5jdGlvbi4gSW4gdGVybXMgb2YgdGhlIG1ldGFwaG9yIG9mIGJha2luZywgd2UgY2FuIHRoaW5rIG9mIHRoaXMgYXMgbGlzdGluZyBvdXIgaW5ncmVkaWVudHMuIFRoZSBuYW1pbmcgY29udmVudGlvbiBmb3IgcmVjaXBlIG9iamVjdCBuYW1lcyBpcyBgKl9yZWNgIG9yIGByZWNgLiAKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjQwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwiU3RhcnRpbmdfYV9yZWNpcGVfcmVjaXBlczEucG5nIikpCmBgYAoKCkluIG91ciBjYXNlIHJlY2FsbCB0aGF0IG91ciBgdmFsdWVgIHZhcmlhYmxlLCB3aGljaCBpcyB0aGUgYXZlcmFnZSBhbm51YWwgZ3JhdmltZXRyaWMgbW9uaXRvciBQTX4yLjV+IGNvbmNlbnRyYXRpb24gaW4gdWcvbV4zXi4gT3VyIHByZWRpY3RvcnMgYXJlIGFsbCB0aGUgb3RoZXIgdmFyaWFibGVzIGV4Y2VwdCB0aGUgbW9uaXRvciBJRCwgd2hpY2ggaXMgYW4gYGlkYCB2YXJpYWJsZS4KClRoZSByZWFzb24gbm90IHRvIGluY2x1ZGUgdGhpcyB2YXJpYWJsZSBpcyBiZWNhdXNlIHRoaXMgdmFyaWFibGUgaW5jbHVkZXMgdGhlIGNvdW50eSBudW1iZXIgYW5kIGEgbnVtYmVyIGRlc2lnbmF0aW5nIHdoaWNoIHBhcnRpY3VsYXIgbW9uaXRvciB0aGUgdmFsdWVzIGNhbWUgZnJvbSBvZiB0aGUgbW9uaXRvcnMgdGhlcmUgYXJlIGluIHRoYXQgY291bnR5LiBTaW5jZSB0aGlzIG51bWJlciBpcyBhcmJpdHJhcnkgYW5kIHRoZSBjb3VudHkgaW5mb3JtYXRpb24gaXMgYWxzbyBnaXZlbiBpbiB0aGUgZGF0YSwgYW5kIHRoZSBmYWN0IHRoYXQgZWFjaCBtb25pdG9yIG9ubHkgaGFzIG9uZSB2YWx1ZSBpbiB0aGUgYHZhbHVlYCB2YXJpYWJsZSwgbm90aGluZyBpcyBnYWluZWQgYnkgaW5jbHVkaW5nIHRoaXMgdmFyaWFibGUgYW5kIGl0IG1heSBpbnN0ZWFkIGludHJvZHVjZSBub2lzZS4gSG93ZXZlciwgaXQgaXMgdXNlZnVsIHRvIGtlZXAgdGhpcyBkYXRhIHRvIHRha2UgYSBsb29rIGF0IHdoYXQgaXMgaGFwcGVuaW5nIGxhdGVyLiBXZSB3aWxsIHNob3cgeW91IHdoYXQgdG8gZG8gaW4gdGhpcyBjYXNlIGluIGp1c3QgYSBiaXQuCgpUaGUgc2ltcGxlc3QgcmVjaXBlIHdpdGggbm8gcHJlcHJvY2Vzc2luZyBzdGVwcywgd291bGQgYmUgdG8gc2ltcGx5IGxpc3QgdGhlIG91dGNvbWUgYW5kIHByZWRpY3RvciB2YXJpYWJsZXMuCgpXZSBjYW4gZG8gc28gaW4gdHdvIHdheXM6ICAKCjEpIFVzaW5nIGZvcm11bGEgbm90YXRpb24gIAoyKSBBc3NpZ25pbmcgcm9sZXMgdG8gZWFjaCB2YXJpYWJsZSAgCgpMZXQncyBsb29rIGF0IHRoZSBmaXJzdCB3YXkgdXNpbmcgZm9ybXVsYSBub3RhdGlvbiwgd2hpY2ggbG9va3MgbGlrZSB0aGlzOiAgCgpvdXRjb21lKHMpIH4gcHJlZGljdG9yKHMpICAKCklmIGluIHRoZSBjYXNlIG9mIG11bHRpcGxlIHByZWRpY3RvcnMgb3IgYSBtdWx0aXZhcmlhdGUgc2l0dWF0aW9uIHdpdGggdHdvIG91dGNvbWVzLCB1c2UgYSBwbHVzIHNpZ24gIAoKb3V0Y29tZTEgKyBvdXRjb21lMiB+IHByZWRpY3RvcjEgKyBwcmVkaWN0b3IyICAKCklmIHdlIHdhbnQgdG8gaW5jbHVkZSBhbGwgcHJlZGljdG9ycyB3ZSBjYW4gdXNlIGEgcGVyaW9kIGxpa2Ugc286ICAKCm91dGNvbWVfdmFyaWFibGVfbmFtZSB+IC4gIAoKTm93IHdpdGggb3VyIGRhdGEgd2Ugd2lsbCBzdGFydCBieSBtYWtpbmcgYSByZWNpcGUgZm9yIG91ciB0cmFpbmluZyBkYXRhLiBJbiB0aGUgc2ltcGxlc3QgY2FzZSB3ZSBtaWdodCB1c2UgYWxsIHByZWRpY3RvcnMgbGlrZSB0aGlzOgoKYGBge3J9CgpzaW1wbGVfcmVjIDwtdHJhaW5fcG0gJT4lCiAgcmVjaXBlczo6cmVjaXBlKHZhbHVlIH4gLikKCnNpbXBsZV9yZWMKYGBgCgoKSG93ZXZlciwgdG8gZGVhbCB3aXRoIHRoZSBpZCB2YXJpYWJsZSB3ZSBjb3VsZCB1c2UgdGhlIGB1cGRhdGVfcm9sZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UuIFRoaXMgb3B0aW9uIHdvcmtzIHdlbGwgd2l0aCB0aGUgbmV3ZXIgYHdvcmtmbG93c2AgcGFja2FnZSwgaG93ZXZlciBpZCB2YXJpYWJsZXMgYXJlIG9mdGVuIGRyb3BwZWQgZnJvbSBhbmFseXNlcyB0aGF0IGRvIG5vdCB1c2UgdGhpcyBuZXdlciBwYWNrYWdlIGFzIHRoZXkgY2FuIG1ha2UgdGhlIHByb2Nlc3MgZGlmZmljdWx0IHdpdGggdXNpbmcgdGhlIGBwYXJzbmlwYCBwYWNrYWdlIGFsb25lIGR1ZSB0byB0aGUgZmFjdCB0aGF0IG5ldyBsZXZlbHMgKG9yIHBvc3NpYmxlIHZhbHVlcykgbWF5IGJlIGludHJvZHVjZWQgd2l0aCB0aGUgdGVzdGluZyBkYXRhLgoKYGBge3J9CgpzaW1wbGVfcmVjIDwtdHJhaW5fcG0gJT4lCiAgcmVjaXBlczo6cmVjaXBlKHZhbHVlIH4gLikgJT4lCiAgcmVjaXBlczo6dXBkYXRlX3JvbGUoaWQsIG5ld19yb2xlID0gImlkIHZhcmlhYmxlIikKCnNpbXBsZV9yZWMKYGBgCgpXZSBjb3VsZCBhbHNvIHNwZWNpZnkgdGhlIG91dGNvbWUgYW5kIHByZWRpY3RvcnMgaW4gdGhlIHNhbWUgd2F5IGFzIHRoZSBpZCB2YXJpYWJsZS4gUGxlYXNlIHNlZSBbaGVyZV0oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby9yZWNpcGVzL3JlZmVyZW5jZS9yZWNpcGUuaHRtbCkgZm9yIGV4YW1wbGVzIG9mIG90aGVyIHJvbGVzIGZvciB2YXJpYWJsZXMuIFRoZSByb2xlIGNhbiBiZSBhY3R1YWxseSBiZSBhbnkgdmFsdWUuIAoKVGhlIG9yZGVyIGlzIGltcG9ydGFudCBoZXJlLCBhcyB3ZSBmaXJzdCBtYWtlIGFsbCB2YXJpYWJsZXMgcHJlZGljdG9ycyBhbmQgdGhlbiBvdmVycmlkZSB0aGlzIHJvbGUgZm9yIHRoZSBvdXRjb21lIGFuZCBpZCB2YXJpYWJsZS4gV2Ugd2lsbCB1c2UgdGhlIGBldmVyeXRoaW5nKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gc3RhcnQgd2l0aCBhbGwgb2YgdGhlIHZhcmlhYmxlcyBpbiBgdHJhaW5fcG1gLgoKYGBge3J9CgpzaW1wbGVfcmVjIDwtcmVjaXBlKHRyYWluX3BtKSAlPiUKICAgIHVwZGF0ZV9yb2xlKGV2ZXJ5dGhpbmcoKSwgbmV3X3JvbGUgPSAicHJlZGljdG9yIiklPiUKICAgIHVwZGF0ZV9yb2xlKHZhbHVlLCBuZXdfcm9sZSA9ICJvdXRjb21lIiklPiUKICAgIHVwZGF0ZV9yb2xlKGlkLCBuZXdfcm9sZSA9ICJpZCB2YXJpYWJsZSIpCgpzaW1wbGVfcmVjCgpgYGAKCklmIHdlIHdhbnQgdG8gdGFrZSBhIGxvb2sgYXQgb3VyIGZvcm11bGEgZnJvbSBvdXIgcmVjaXBlIHdlIGNhbiBkbyB1c2UgdGhlIGBmb3JtdWxhKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RhdHNgIHBhY2thZ2UuCgpgYGB7cn0KZm9ybXVsYShzaW1wbGVfcmVjKQpgYGAKCldlIGNhbiBhbHNvIHZpZXcgb3VyIHJlY2lwZSBpbiBtb3JlIGRldGFpbCB1c2luZyB0aGUgYmFzZSBgc3VtbWFyeSgpYCBmdW5jdGlvbi4KCmBgYHtyfQpzdW1tYXJ5KHNpbXBsZV9yZWMpCmBgYAoKIyMjIyBMaXN0IHRoZSBwcmVwcm9jZXNzaW5nIHN0ZXBzIHVzaW5nIHRoZSBzdGVwIGZ1bmN0aW9ucyBvZiB0aGUgYHJlY2lwZWAgcGFja2FnZQoKVGhlIG90aGVyIHRoaW5nIHRoZSByZWNpcGVzIHBhY2thZ2UgYWxsb3dzIGZvciBpcyBzcGVjaWZ5aW5nIHByZXByb2Nlc3Npbmcgc3RlcHMgdXNpbmcgYSB2YXJpZXR5IG9mIGBzdGVwKigpYCBmdW5jdGlvbnMuCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI0MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsIk1ha2luZ19hX3JlY2lwZV9yZWNpcGVzMi5wbmciKSkKYGBgCgoKKipUaGlzIFtsaW5rXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3JlY2lwZXMvcmVmZXJlbmNlL2luZGV4Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gYW5kIHRoaXMgW2xpbmtdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yZWNpcGVzL3JlY2lwZXMucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHNob3cgdGhlIG1hbnkgb3B0aW9ucyBmb3IgcmVjaXBlIHN0ZXAgZnVuY3Rpb25zLioqCgo8dT5UaGVyZSBhcmUgc3RlcCBmdW5jdGlvbnMgZm9yIGEgdmFyaWV0eSBvZiBwdXJwb3Nlczo8L3U+CgoxKSBbKipJbXB1dGF0aW9uKipdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0ltcHV0YXRpb25fKHN0YXRpc3RpY3MpKXt0YXJnZXQ9Il9ibGFuayJ9ICAtLSB3aGljaCBtZWFucyBmaWxsaW5nIGluIG1pc3NpbmcgdmFsdWVzIGJhc2VkIG9uIHRoZSBleGlzdGluZyBkYXRhIAoyKSBbKipUcmFuc2Zvcm1hdGlvbioqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EYXRhX3RyYW5zZm9ybWF0aW9uXyhzdGF0aXN0aWNzKSl7dGFyZ2V0PSJfYmxhbmsifSAgLS0gd2hpY2ggbWVhbnMgY2hhbmdpbmcgYWxsIHZhbHVlcyBvZiBhIHZhcmlhYmxlIGluIHRoZSBzYW1lIHdheSwgdHlwaWNhbGx5IHRvIG1ha2UgaXQgbW9yZSBub3JtYWwgb3IgZWFzaWVyIHRvIGludGVycHJldCkgIAozKSBbKipEaXNjcmV0aXphdGlvbioqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EaXNjcmV0aXphdGlvbl9vZl9jb250aW51b3VzX2ZlYXR1cmVzKSAtLSB3aGljaCBtZWFucyBjb252ZXJ0aW5nIGNvbnRpbnVvdXMgdmFsdWVzIGludG8gZGlzY3JldGUgb3Igbm9taW5hbCB2YWx1ZXMgLSBiaW5uaW5nIGZvciBleGFtcGxlIHRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIHBvc3NpYmxlIGxldmVscykgIChIb3dldmVyIHRoaXMgaXMgZ2VuZXJhbGx5IG5vdCBhZHZpc2FibGUhKQo0KSBbKipFbmNvZGluZyAvIENyZWF0aW5nIER1bW15IFZhcmlhYmxlcyoqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EdW1teV92YXJpYWJsZV8oc3RhdGlzdGljcykpIC0tIHdoaWNoIG1lYW5zIGNyZWF0aW5nIGEgbnVtZXJpYyBjb2RlIGZvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKWyoqTW9yZSBvbiBEdW1teSBWYXJpYWJsZXMgYW5kIG9uZSBob3QgZW5jb2RpbmcqKl0oaHR0cHM6Ly9tZWRpdW0uY29tL3AvYjU4NDBiZTNjNDFhL3Jlc3BvbnNlcy9zaG93KQo1KSBbKipEYXRhIHR5cGUgY29udmVyc2lvbnMqKl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2hhYmxhci92aWduZXR0ZXMvY29udmVydC5odG1sKSAtLSB3aGljaCBtZWFucyBjaGFuZ2luZyBmcm9tIGludGVnZXIgdG8gZmFjdG9yIG9yIG51bWVyaWMgdG8gZGF0ZSBldGMuCjYpIFsqKkludGVyYWN0aW9uKipdKGh0dHBzOi8vc3RhdGlzdGljc2J5amltLmNvbS9yZWdyZXNzaW9uL2ludGVyYWN0aW9uLWVmZmVjdHMvKSB0ZXJtIGFkZGl0aW9uIHRvIHRoZSBtb2RlbCAtLSB3aGljaCBtZWFucyB0aGF0IHdlIHdvdWxkIGJlIG1vZGVsaW5nIGZvciBwcmVkaWN0b3JzIHRoYXQgd291bGQgaW5mbHVlbmNlIHRoZSBjYXBhY2l0eSBvZiBlYWNoIG90aGVyIHRvIHByZWRpY3QgdGhlIG91dGNvbWUKNykgWyoqTm9ybWFsaXphdGlvbioqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Ob3JtYWxpemF0aW9uXyhzdGF0aXN0aWNzKSkgLS0gd2hpY2ggbWVhbnMgY2VudGVyaW5nIGFuZCBzY2FsaW5nIHRoZSBkYXRhIHRvIGEgc2ltaWxhciByYW5nZSBvZiB2YWx1ZXMKOCkgWyoqRGltZW5zaW9uYWxpdHkgUmVkdWN0aW9uLyBTaWduYWwgRXh0cmFjdGlvbioqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EaW1lbnNpb25hbGl0eV9yZWR1Y3Rpb24pIC0tIHdoaWNoIG1lYW5zIG1hdGhlbWF0aWNhbGx5IG9idGFpbmluZyBhIG5ldyBzbWFsbGVyIHNldCBvZiB2YXJpYWJsZXMgdGhhdCBjYXB0dXJlIHRoZSB2YXJpYXRpb24gb3Igc2lnbmFsIGluIHRoZSBvcmlnaW5hbCB2YXJpYWJsZXMgKGV4LiBQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzIGFuZCBJbmRlcGVuZGVudCBDb21wb25lbnQgQW5hbHlzaXMpCjkpICoqRmlsdGVyaW5nKiogLS0gRmlsdGVyaW5nIG9wdGlvbnMgZm9yIHJlbW92aW5nIHZhcmlhYmxlcyAoZXguIHJlbW92ZSB2YXJpYWJsZXMgdGhhdCBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQgdG8gb3RoZXJzIG9yIHJlbW92ZSB2YXJpYWJsZXMgd2l0aCB2ZXJ5IGxpdHRsZSB2YXJpYW5jZSBhbmQgdGhlcmVmb3JlIGxpa2VseSBsaXR0bGUgcHJlZGljdGl2ZSBjYXBhY2l0eSkKMTApIFsqKlJvdyBvcGVyYXRpb25zKipdKGh0dHBzOi8vdGFydGFydXMub3JnL2dhcmV0aC9tYXRocy9MaW5lYXJfQWxnZWJyYS9yb3dfb3BlcmF0aW9ucy5wZGYpIC0tIHdoaWNoIG1lYW5zIHBlcmZvcm1pbmcgZnVuY3Rpb25zIG9uIHRoZSB2YWx1ZXMgd2l0aGluIHRoZSByb3dzICAoZXguIHJlYXJyYW5naW5nLCBmaWx0ZXJpbmcsIGltcHV0aW5nKQoxMSkgKipDaGVja2luZyBmdW5jdGlvbnMqKiAtLSBTYW5pdHkgY2hlY2tzIHRvIGxvb2sgZm9yIG1pc3NpbmcgdmFsdWVzLCB0byBsb29rIGF0IHRoZSB2YXJpYWJsZSBjbGFzc2VzIGV0Yy4KCkFsbCBvZiB0aGUgc3RlcCBmdW5jdGlvbnMgbG9vayBsaWtlIGBzdGVwXypgIGV4Y2VwdCBmb3IgdGhlIGNoZWNrIGZ1bmN0aW9ucyB3aGljaCBsb29rIGxpa2UgYGNoZWNrXypgLgoKVGhlcmUgYXJlIHNldmVyYWwgd2F5cyB0byBzZWxlY3Qgd2hhdCB2YXJpYWJsZXMgdG8gYXBwbHkgc3RlcHMgdG86ICAKMSkgdGlkeXNlbGVjdCBtZXRob2RzOiBgY29udGFpbnMoKWAsIGBtYXRjaGVzKClgLCBgc3RhcnRzX3dpdGgoKWAsIGBlbmRzX3dpdGgoKWAsIGBldmVyeXRoaW5nKClgLCBgbnVtX3JhbmdlKClgICAKMikgYmFzZWQgb24gdGhlIHR5cGU6IGBhbGxfbm9taW5hbCgpYCwgYGFsbF9udW1lcmljKClgICwgYGhhc190eXBlKClgIAozKSBiYXNlZCBvbiB0aGUgcm9sZTogYGFsbF9wcmVkaWN0b3JzKClgLCBgYWxsX291dGNvbWVzKClgLCBgaGFzX3JvbGUoKWAKNCkgbmFtZSAtIHVzZSB0aGUgYWN0dWFsIG5hbWUgb2YgdGhlIHZhcmlhYmxlL3ZhcmlhYmxlcyBvZiBpbnRlcmVzdCAgCgoKTGV0J3MgdHJ5IGFkZGluZyBzb21lIHN0ZXBzIHRvIG91ciByZWNpcGUuCgpXZSBtaWdodCBjb25zaWRlciBsb2cgdHJhbnNmb3JtaW5nIG91ciBwb3B1bGF0aW9uIGFuZCBhcmVhIHZhcmlhYmxlcyAodGhhdCBhcmVuJ3QgZGVuc2l0aWVzKSAtIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSByYW5nZSBvZiB0aGVzZSB2YXJpYWJsZXMuCmBgYHtyLCBldmFsID0gRkFMU0V9CnBtICU+JQogIHNlbGVjdChtYXRjaGVzKCJfcG9wfF9hcmVhIikpICU+JQogIG1hcChyYW5nZSkKYGBgCldlIGNhbiBzZWUgdGhhdCB0aGUgcmFuZ2UgZm9yIGVhY2ggb2YgdGhlc2UgdmFyaWFibGVzIGlzIHF1aXRlIGxhcmdlLCB3ZSBjYW4gbG9nIHRyYW5zZm9ybSB0aGlzIGRhdGEgdXNpbmcgdGhlIGBzdGVwX2xvZygpYCBmdW5jdGlvbiBvZiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UuCgpXZSB3b3VsZCBhbHNvIHdhbnQgdG8gcG90ZW50aWFsbHkgW29uZSBob3QgZW5jb2RlXShodHRwczovL21hY2hpbmVsZWFybmluZ21hc3RlcnkuY29tL3doeS1vbmUtaG90LWVuY29kZS1kYXRhLWluLW1hY2hpbmUtbGVhcm5pbmcvKSBzb21lIG9mIG91ciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgc28gdGhhdCB0aGV5IGNhbiBiZSB1c2VkIHdpdGggY2VydGFpbiBhbGdvcml0aG1zLiBXZSBjYW4gZG8gdGhpcyB3aXRoIHRoZSBgc3RlcF9kdW1teSgpYCBmdW5jdGlvbiBhbmQgdGhlIGBvbmVfaG90ID0gVFJVRWAgYXJndW1lbnQuIG9uZSBob3QgZW5jb2RpbmcgbWVhbnMgdGhhdCB3ZSBkb24ndCBqdXN0IHNpbXBseSBlbmNvZGUgb3VyIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBudW1lcmljYWxseSwgYXMgb3VyIG51bWVyaWMgYXNzaWdubWVudHMgY2FuIGJlIGludGVycHJldGVkIGJ5IGFsZ29yaXRobXMgYXMgaGF2aW5nIGEgcGFydGljdWxhciByYW5rIG9yIG9yZGVyLiBJbnN0ZWFkLCBiaW5hcnkgdmFyaWFibGVzIG1hZGUgb2YgMXMgYW5kIDBzIGFyZSB1c2VkIHRvIGFyYml0cmFyaWx5IGFzc2lnbiBhIG51bWVyaWMgdmFsdWUgdGhhdCBoYXMgbm8gYXBwYXJlbnQgb3JkZXIuCgpPdXIgZmlwcyB2YXJpYWJsZSBpbmNsdWRlcyBhIG51bWVyaWMgY29kZSBmb3Igc3RhdGUgYW5kIGNvdW50eSAtIGFuZCB0aGVyZWZvcmUgaXMgZXNzZW50aWFsbHkgYSBwcm94eSBmb3IgY291bnR5LiAgU2luY2Ugd2UgYWxyZWFkeSBoYXZlIGNvdW50eSwgd2Ugd2lsbCBqdXN0IHVzZSBpdCBhbmQga2VlcCB0aGUgZmlwcyBpZCBhcyBhbm90aGVyIElEIHZhcmlhYmxlLgoKV2UgY2FuIHJlbW92ZSB0aGUgYGZpcHNgIHZhcmlhYmxlIGZyb20gdGhlIHByZWRpY3RvcnMgdXNpbmcgYHVwZGF0ZV9yb2xlKClgIHRvIG1ha2Ugc3VyZSB0aGF0IHRoZSByb2xlIGlzIG5vIGxvbmdlciBgInByZWRpY3RvciJgLiBXZSBjYW4gbWFrZSB0aGUgcm9sZSBhbnl0aGluZyB3ZSB3YW50IGFjdHVhbGx5LCBzbyB3ZSB3aWxsIGtlZXAgaXQgc29tZXRoaW5nIGlkZW50aWZpYWJsZS4KCldlIG1pZ2h0IGFsc28gd2FudCB0byByZW1vdmUgdmFyaWFibGVzIHRoYXQgYXBwZWFyIHRvIGJlIHJlZHVuZGFudCBhbmQgYXJlIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggb3RoZXJzLCBhcyB3ZSBrbm93IGZyb20gb3VyIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgdGhhdCBtYW55IG9mIG91ciB2YXJpYWJsZXMgYXJlIGNvcnJlbGF0ZWQgd2l0aCBvbmUgYW5vdGhlci4gV2UgY2FuIGRvIHRoaXMgdXNpbmcgdGhlIGBzdGVwX2NvcnIoKWAgZnVuY3Rpb24uCgpJdCBpcyBhbHNvIGEgZ29vZCBpZGVhIHRvIHJlbW92ZSB2YXJpYWJsZXMgd2l0aCBuZWFyLXplcm8gdmFyaWFuY2UsIHdoaWNoIGNhbiBiZSBkb25lIHdpdGggdGhlIGBzdGVwX256digpYCBmdW5jdGlvbi4gVmFyaWFibGVzIGhhdmUgbG93IHZhcmlhbmNlIGlmIGFsbCB0aGUgdmFsdWVzIGFyZSB2ZXJ5IHNpbWlsYXIsIHRoZSB2YWx1ZXMgYXJlIHZlcnkgc3BhcnNlLCBvciBpZiB0aGV5IGFyZSBoaWdobHkgaW1iYWxhbmNlZC4gCgpFeGFtcGxlcyB3aGVyZSB5b3UgbWlnaHQgaGF2ZSBuZWFyLXplcm8gdmFyaWFuY2UgdmFyaWFibGVzIGluY2x1ZGU6IAoKMSkgKipTaW1pbGFyIFZhbHVlcyoqIC0gSWYgdGhlIHBvcHVsYXRpb24gZGVuc2l0eSB3YXMgbmVhcmx5IHRoZSBzYW1lIGZvciBldmVyeSB6Y3RhIHRoYXQgY29udGFpbmVkIGEgbW9uaXRvciwgdGhlbiBrbm93aW5nIHRoZSBwb3B1bGF0aW9uIGRlbnNpdHkgbmVhciBvdXIgbW9uaXRvciB3b3VsZCBjb250cmlidXRlIGxpdHRsZSB0byBvdXIgbW9kZWwgaW4gYXNzaXN0aW5nIHVzIHRvIHByZWRpY3QgbW9uaXRvciBhaXIgcG9sbHV0aW9uIHZhbHVlcy4gCjIpICoqU3BhcnNlIERhdGEqKiAtIElmIGFsbCBvZiB0aGUgbW9uaXRvcnMgd2VyZSBpbiBsb2NhdGlvbnMgd2hlcmUgdGhlIHBvcHVsYXRpb25zIGRpZCBub3QgYXR0ZW5kIGdyYWR1YXRlIHNjaG9vbCwgdGhlbiB0aGVzZSB2YWx1ZXMgd291bGQgbW9zdGx5IGJlIHplcm8sIGFnYWluIHRoaXMgd291bGQgZG8gdmVyeSBsaXR0bGUgdG8gaGVscCB1cyBkaXN0aW5ndWlzaCBvdXIgYWlyIHBvbGx1dGlvbiBtb25pdG9ycy5XaGVuIG1hbnkgb2YgdGhlIHZhbHVlcyBhcmUgemVybyB0aGlzIGlzIGFsc28gY2FsbGVkIHNwYXJzZSBkYXRhLiAgCjMpICoqSW1iYWxhbmNlZCBEYXRhKiogSWYgbmVhcmx5IGFsbCBvZiB0aGUgbW9uaXRvcnMgd2VyZSBsb2NhdGVkIGluIG9uZSBwYXJ0aWN1bGFyIHN0YXRlLCBhbmQgYWxsIHRoZSBvdGhlcnMgb25seSBoYWQgb25lIG1vbml0b3IgZWFjaCwgdGhlbiB0aGUgcmVhbCBwcmVkaWN0aXZlIHZhbHVlIHdvdWxkIHNpbXBseSBiZSBpbiBrbm93aW5nIGlmIGEgbW9uaXRvciBpcyBsb2NhdGVkIGluIHRoYXQgcGFydGljdWxhciBzdGF0ZSBvciBub3QuIEluIHRoaXMgY2FzZSB3ZSBkb24ndCB3YW50IHRvIHJlbW92ZSBvdXIgdmFyaWFibGUsIHdlIGp1c3Qgd2FudCB0byBzaW1wbGlmeSBpdC4KClNlZSB0aGlzIFtibG9nIHBvc3RdKGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tL25lYXItemVyby12YXJpYW5jZS1wcmVkaWN0b3JzLXNob3VsZC13ZS1yZW1vdmUtdGhlbS8pIGFib3V0IHdoeSByZW1vdmluZyBuZWFyLXplcm8gdmFyaWFuY2UgdmFyaWFibGVzIGlzbid0IGFsd2F5cyBhIGdvb2QgaWRlYSBpZiB3ZSB0aGluayB0aGF0IGEgdmFyaWFibGUgbWlnaHQgYmUgZXNwZWNpYWxseSBpbmZvcm1hdGl2ZS4KCioqSXQgaXMgaW1wb3J0YW50IHRvIGFkZCB0aGUgc3RlcHMgdG8gdGhlIHJlY2lwZSBpbiBhbiBvcmRlciB0aGF0IG1ha2VzIHNlbnNlIGp1c3QgbGlrZSB3aXRoIGEgY29va2luZyByZWNpcGUuKioKClRodXMgZmlyc3Qgd2UgYXJlIGdvaW5nIHRvIGNyZWF0ZSBudW1lcmljIHZhbHVlcyBmb3Igb3VyIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgdGhlbiB3ZSB3aWxsIGxvb2sgYXQgY29ycmVsYXRpb24gYW5kIG5lYXItemVybyB2YXJpYW5jZS4gV2UgZG9uJ3Qgd2FudCB0byByZW1vdmUgc29tZSBvZiBvdXIgdmFyaWFibGVzLCBsaWtlIHRoZSBDTUFRIGFuZCBhb2QgdmFyaWFibGVzIHNvIHdlIGNhbiBtYWtlIHN1cmUgdGhleSBhcmUga2VwdCBpbiB0aGUgbW9kZWwgYnkgZXhjbHVkaW5nIHRoZW0gZnJvbSB0aG9zZSBzdGVwcy4gSWYgd2Ugc3BlY2lmaWNhbGx5IHdhbnRlZCB0byByZW1vdmUgYSBwcmVkaWN0b3Igd2UgY291bGQgdXNlIGBzdGVwX3JtKClgLgoKYGBge3J9CnNpbXBsZV9yZWMgJTw+JQogIHVwZGF0ZV9yb2xlKCJmaXBzIiwgbmV3X3JvbGUgPSAiY291bnR5IGlkIikgJT4lCiMgY3JlYXRlIG51bWVyaWMgZHVtbXkgdmFyaWFibGVzIHRvIGVuY29kZSBmb3IgY2F0ZWdvcmljYWwgdmFyaWFibGVzCiAgc3RlcF9kdW1teShzdGF0ZSwgY291bnR5LCBjaXR5LCB6Y3RhLCBvbmVfaG90ID0gVFJVRSkgJT4lCiAgIyBpZGVudGlmeSBhbmQgcmVtb3ZlIGFsbCBjb3JyZWxhdGVkIHByZWRpY3RvcnMgKG5vdyB0aGF0IHRoZXkgYXJlIG51bWVyaWMpCiAgc3RlcF9jb3JyKGFsbF9wcmVkaWN0b3JzKCksIC0gQ01BUSwgLSBhb2QpJT4lCiAgIyBpZGVudGlmeSB2YXJpYWJsZXMgd2l0aCBuZWFyIHplcm8gdmFyaWFuY2UgYW5kIHJlbW92ZQogIHN0ZXBfbnp2KGFsbF9wcmVkaWN0b3JzKCksIC0gQ01BUSwgLSBhb2QpCiAgCnNpbXBsZV9yZWMKCmBgYAoKCgojIyMgUnVubmluZyB0aGUgcHJlcHJvY2Vzc2luZwoKVGhlIG5leHQgbWFqb3IgZnVuY3Rpb24gb2YgdGhlIGByZWNpcGVzYCBwYWNrYWdlIGlzIGBwcmVwKClgLgoKVGhpcyBmdW5jdGlvbiB1cGRhdGVzIHRoZSByZWNpcGUgb2JqZWN0IGJhc2VkIG9uIHRoZSB0cmFpbmluZyBkYXRhLiBJdCBlc3RpbWF0ZXMgcGFyYW1ldGVycyAoZXN0aW1hdGluZyB0aGUgcmVxdWlyZWQgcXVhbnRpdGllcyBhbmQgc3RhdGlzdGljcyByZXF1aXJlZCBieSB0aGUgc3RlcHMgZm9yIHRoZSB2YXJpYWJsZXMpIGZvciBwcmVwcm9jZXNzaW5nIGFuZCAgdXBkYXRlcyB0aGUgbW9kZWwgdGVybXMsIGFzIHNvbWUgb2YgdGhlIHByZWRpY3RvcnMgbWF5IGJlIHJlbW92ZWQsIHRoaXMgYWxsb3dzIHRoZSByZWNpcGUgdG8gYmUgcmVhZHkgdG8gdXNlIG9uIG90aGVyIGRhdGFzZXRzLiBJdCBkb2Vzbid0IG5lY2Vzc2FyaWx5IGFjdHVhbGx5IGV4ZWN1dGUgdGhlIHByZXByb2Nlc3NpbmcgaXRzZWxmLCBob3dldmVyIHdlIHdpbGwgc3BlY2lmeSBpbiBhcmd1bWVudCBmb3IgaXQgdG8gZG8gdGhpcyBzbyB0aGF0IHdlIGNhbiB0YWtlIGEgbG9vayBhdCB0aGUgcHJlcHJvY2Vzc2VkIGRhdGEuCgpUaGVyZSBhcmUgc29tZSBpbXBvcnRhbnQgYXJndW1lbnRzIHRvIGtub3cgYWJvdXQ6CjEpIHRyYWluaW5nIC0geW91IG11c3Qgc3VwcGx5IGEgdHJhaW5pbmcgZGF0YSBzZXQgdG8gZXN0aW1hdGUgcGFyYW1ldGVycyBmb3IgcHJlcHJvY2Vzc2luZyBvcGVyYXRpb25zIChyZWNpcGUgc3RlcHMpIC0gdGhpcyBtYXkgYWxyZWFkeSBiZSBpbmNsdWRlZCBpbiB5b3VyIHJlY2lwZSAtIGFzIGlzIHRoZSBjYXNlIGZvciB1cwoyKSBmcmVzaCAtIGlmIFRSVUUgLSB3aWxsIHJldHJhaW4gYW5kIGVzdGltYXRlIHBhcmFtZXRlcnMgZm9yIGFueSBwcmV2aW91cyBzdGVwcyB0aGF0IHdlcmUgYWxyZWFkeSBwcmVwcGVkIGlmIHlvdSBhZGQgbW9yZSBzdGVwcyB0byB0aGUgcmVjaXBlCjMpIHZlcmJvc2UgLSBpZiBgVFJVRWAgc2hvd3MgdGhlIHByb2dyZXNzIGFzIHRoZSBzdGVwcyBhcmUgZXZhbHVhdGVkIGFuZCB0aGUgc2l6ZSBvZiB0aGUgcHJlcHJvY2Vzc2VkIHRyYWluaW5nIHNldAo0KSByZXRhaW4gLSBpZiBgVFJVRWAgdGhlbiB0aGUgcHJlcHJvY2Vzc2VkIHRyYWluaW5nIHNldCB3aWxsIGJlIHNhdmVkIHdpdGhpbiB0aGUgcmVjaXBlIChhcyB0ZW1wbGF0ZSkuIFRoaXMgaXMgZ29vZCBpZiB5b3UgYXJlIGxpa2VseSB0byBhZGQgbW9yZSBzdGVwcyBhbmQgZG9uJ3Qgd2FudCB0byByZXJ1biB0aGUgYHByZXAoKWAgb24gdGhlIHByZXZpb3VzIHN0ZXBzLiBIb3dldmVyIHRoaXMgY2FuIG1ha2UgdGhlIHJlY2lwZSBzaXplIGxhcmdlLiBUaGlzIGlzIG5lY2Vzc2FyeSBpZiB5b3Ugd2FudCB0byBhY3R1YWxseSBsb29rIGF0IHRoZSBwcmVwcm9jZXNzZWQgZGF0YS4KCgpgYGB7cn0KcHJlcHBlZF9yZWMgPC0gcHJlcChzaW1wbGVfcmVjLCB2ZXJib3NlID0gVFJVRSwgcmV0YWluID0gVFJVRSApCm5hbWVzKHByZXBwZWRfcmVjKQpgYGAKClRoZXJlIGFyZSBhbHNvIGxvdHMgb2YgdXNlZnVsIHRoaW5ncyB0byBjaGVja291dCBpbiB0aGUgb3V0cHV0IG9mIGBwcmVwKClgLgpZb3UgY2FuIHNlZToKMSkgdGhlIGBzdGVwc2AgdGhhdCB3ZXJlIHJ1biAgCjIpIHRoZSB2YXJpYWJsZSBpbmZvIChgdmFyX2luZm9gKSAgCjMpIHRoZSBtb2RlbCBgdGVybV9pbmZvYAo0KSB0aGUgbmV3IGBsZXZlbHNgIG9mIHRoZSB2YXJpYWJsZXMgCjUpIHRoZSBvcmlnaW5hbCBsZXZlbHMgb2YgdGhlIHZhcmlhYmxlcyBgb3JpZ19sdmxzYCAgIAo2KSBpbmZvIGFib3V0IHRoZSB0cmFpbmluZyBkYXRhIHNldCBzaXplIGFuZCBjb21wbGV0ZW5lc3MgKGB0cl9pbmZvYCkKCk5vdGU6ICBZb3UgbWF5IHNlZSB0aGUgYHByZXAucmVjaXBlKClgIGZ1bmN0aW9uIGluIG1hdGVyaWFsIHRoYXQgeW91IHJlYWQgYWJvdXQgdGhlIGByZWNpcGVzYCBwYWNrYWdlLiBUaGlzIGlzIHJlZmVycmluZyB0byB0aGUgYHByZXAoKWAgZnVuY3Rpb24gb2YgdGhlIGByZWNpcGVzYCBwYWNrYWdlLgoKIyMjIyBFeHRyYWN0aW5nIHRoZSBwcmVwcm9jZXNzZWQgdHJhaW5pbmcgZGF0YQoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNDAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJ0cmFpbmluZ19wcmVwcm9jZXNzaW5nX3JlY2lwZXMzLnBuZyIpKQpgYGAKClNpbmNlIHdlIHJldGFpbmVkIG91ciBwcmVwcm9jZXNzZWQgdHJhaW5pbmcgZGF0YSwgd2UgY2FuIHRha2UgYSBsb29rIGF0IGl0IGxpa2UgYnkgdXNpbmcgdGhlIGBqdWljZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UgbGlrZSB0aGlzOgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cn0KIyBTY3JvbGwgdGhlcm91Z2ggdGhlIG91dHB1dCEKanVpY2VkX3RyYWluPC0ganVpY2UocHJlcHBlZF9yZWMpCmdsaW1wc2UoanVpY2VkX3RyYWluKQpgYGAKIyMjIwoKCkZvciBlYXN5IGNvbXBhcmlzb24gc2FrZSAtIGhlcmUgaXMgb3VyIG9yaWdpbmFsIGRhdGE6CgojIyMjIHsuc2Nyb2xsYWJsZSB9CgpgYGB7cn0KIyBTY3JvbGwgdGhlcm91Z2ggdGhlIG91dHB1dCEKZ2xpbXBzZShwbSkKYGBgCiMjIyMKCk5vdGljZSBob3cgd2Ugb25seSBoYXZlIDM2IHZhcmlhYmxlcyBub3cgaW5zdGVhZCBvZiA1MCEgVHdvIG9mIHRoZXNlIGFyZSBvdXIgSUQgdmFyaWFibGVzIChgZmlwc2AgYW5kIHRoZSBhY3R1YWwgbW9uaXRvciBJRCAoYGlkYCkpIGFuZCBvbmUgaXMgb3VyIG91dGNvbWUgKGB2YWx1ZWApLiBUaHVzIHdlIG9ubHkgaGF2ZSAzMyBwcmVkaWN0b3JzIG5vdy4gV2UgY2FuIGFsc28gc2VlIHRoYXQgdmFyaWFibGVzIHRoYXQgd2Ugbm8gbG9uZ2VyIGhhdmUgYW55IGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gVmFyaWFibGVzIGxpa2UgYHN0YXRlYCBhcmUgZ29uZSBhbmQgb25seSBgc3RhdGVfQ2FsaWZvcm5pYWAgcmVtYWlucyBhcyBpdCB3YXMgdGhlIG9ubHkgc3RhdGUgaWRlbnRpdHkgdG8gaGF2ZSBub256ZXJvIHZhcmlhbmNlLiAgV2UgY2FuIHNlZSB0aGF0IENhbGlmb3JuaWEgaGFkIHRoZSBsYXJnZXN0IG51bWJlciBvZiBtb25pdG9ycyBjb21wYXJlZCB0byB0aGUgb3RoZXIgc3RhdGVzLiBXZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGVyZSB3ZXJlIG1vcmUgbW9uaXRvcnMgbGlzdGVkIGFzIGAiTm90IGluIGEgY2l0eSJgIHRoYW4gYW55IGNpdHkuIAoKIyMjIyB7LnNjcm9sbGFibGUgfQoKYGBge3J9CiNTY3JvbGwgdGhyb3VnaCB0aGUgb3V0cHV0IQpwbSAlPiUgY291bnQoc3RhdGUpICAlPiUKICBwcmludChuID0gMWUzKQpgYGAKCiMjIyMKCiMjIyMgey5zY3JvbGxhYmxlIH0KCmBgYHtyfQojU2Nyb2xsIHRocm91Z2ggdGhlIG91dHB1dCEKcG0gJT4lIGNvdW50KGNpdHkpICU+JQogIHByaW50KG4gPSAxZTMpCmBgYAoKIyMjIwoKKipOb3RlKio6ICBSZWNhbGwgdGhhdCB5b3UgbXVzdCBzcGVjaWZ5IGByZXRhaW4gPSBUUlVFYCBhcmd1bWVudCBvZiB0aGUgYHByZXAoKWAgZnVuY3Rpb24gdG8gdXNlIGBqdWljZSgpYC4KCiMjIyMgRXh0cmFjdGluZyB0aGUgcHJlcHJvY2Vzc2VkIHRlc3RpbmcgZGF0YQoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNDAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJ0ZXN0aW5nX3ByZXByb2Nlc3NpbmdfcmVjaXBlczQucG5nIikpCmBgYAoKQWNjb3JkaW5nIHRvIHRoZSB0aWR5bW9kZWxzIGRvY3VtZW50YXRpb246Cgo+IGBiYWtlKClgIHRha2VzIGEgdHJhaW5lZCByZWNpcGUgYW5kIGFwcGxpZXMgdGhlIG9wZXJhdGlvbnMgdG8gYSBkYXRhIHNldCB0byBjcmVhdGUgYSBkZXNpZ24gbWF0cml4LgogZm9yIGV4YW1wbGU6ICBpdCBhcHBsaWVzIHRoZSBjZW50ZXJpbmcgdG8gbmV3IGRhdGEgc2V0cyB1c2luZyB0aGVzZSBtZWFucyB1c2VkIHRvIGNyZWF0ZSB0aGUgcmVjaXBlCgoKSWYgeW91IHdhbnRlZCB0byBsb29rIGF0IHRoZSBwcmVwcm9jZXNzZWQgdGVzdGluZyBkYXRhIHlvdSB3b3VsZCB1c2UgdGhlIGBiYWtlKClgIGZ1bmN0aW9uIG9mIHRoZSBgcmVjaXBlc2AgcGFja2FnZS4KKFlvdSBnZW5lcmFsbHkgd2FudCB0byBsZWF2ZSB5b3VyIHRlc3RpbmcgZGF0YSBhbG9uZSwgYnV0IGl0IGlzIGdvb2QgdG8gbG9vayBmb3IgaXNzdWVzIGxpa2UgdGhlIGludHJvZHVjdGlvbiBvZiBOQSB2YWx1ZXMpLgoKIyMjIyB7LnNjcm9sbGFibGUgfQpgYGB7cix9CiMgU2Nyb2xsIHRoZXJvdWdoIHRoZSBvdXRwdXQhCmJha2VkX3Rlc3RfcG0gPC0gcmVjaXBlczo6YmFrZShwcmVwcGVkX3JlYywgbmV3X2RhdGEgPSB0ZXN0X3BtKQpnbGltcHNlKGJha2VkX3Rlc3RfcG0gKQpgYGAKIyMjIwoKCk5vdGljZSB0aGF0IG91ciBgY2l0eV9Ob3QuaW4uYS5jaXR5YCB2YXJpYWJsZSBzZWVtcyB0byBiZSBOQSB2YWx1ZXMuIFdoeSBtaWdodCB0aGF0IGJlPwoKQWghIFBlcmhhcHMgaXQgaXMgYmVjYXVzZSBzb21lIG9mIG91ciBsZXZlbHMgd2VyZSBub3QgcHJldmlvdXNseSBzZWVuIGluIHRoZSB0cmFpbmluZyBzZXQhCgpMZXQncyB0YWtlIGEgbG9vayB1c2luZyB0aGUgW3NldCBvcGVyYXRpb25zXShodHRwczovL3d3dy5wcm9iYWJpbGl0eWNvdXJzZS5jb20vY2hhcHRlcjEvMV8yXzJfc2V0X29wZXJhdGlvbnMucGhwKSBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBXZSBjYW4gdGFrZSBhIGxvb2sgYXQgY2l0aWVzIHRoYXQgd2VyZSBkaWZmZXJlbnQgYmV0d2VlbiB0aGUgdGVzdCBhbmQgdHJhaW5pbmcgc2V0LgoKYGBge3J9CnRyYWluY2l0aWVzIDwtIHRyYWluX3BtICU+JSBkaXN0aW5jdChjaXR5KQp0ZXN0Y2l0aWVzIDwtIHRlc3RfcG0gJT4lIGRpc3RpbmN0KGNpdHkpCgojZ2V0IHRoZSBudW1iZXIgb2YgY2l0aWVzIHRoYXQgd2VyZSBkaWZmZXJlbnQKZGltKGRwbHlyOjpzZXRkaWZmKHRyYWluY2l0aWVzLCB0ZXN0Y2l0aWVzKSkKCiNnZXQgdGhlIG51bWJlciBvZiBjaXRpZXMgdGhhdCBvdmVybGFwcGVkCmRpbShkcGx5cjo6aW50ZXJzZWN0KHRyYWluY2l0aWVzLCB0ZXN0Y2l0aWVzKSkKYGBgCgpJbmRlZWQsIHRoZXJlIGFyZSBsb3RzIG9mIGRpZmZlcmVudCBjaXRpZXMgaW4gb3VyIHRlc3QgZGF0YSB0aGF0IGFyZSBub3QgaW4gb3VyIHRyYWluaW5nIGRhdGEhCgpNYXliZSByZW1vdmUgdGhpcz86IFRodXMgd2UgbmVlZCB0byB1cGRhdGUgb3VyIG9yaWdpbmFsIHJlY2lwZSB0byBpbmNsdWRlIGEgdmVyeSBpbXBvcnRhbnQgc3RlcCBmdW5jdGlvbiBjYWxsZWQgYHN0ZXBfbm92ZWwoKWAgdGhpcyBoZWxwcyBpbiBjYXNlcyBsaWtlIHRoaXMgd2VyZSB0aGVyZSBhcmUgbmV3IGZhY3RvcnMgaW4gb3VyIHRlc3Rpbmcgc2V0IHRoYXQgd2VyZSBub3QgaW4gb3VyIHRyYWluaW5nIHNldC4gSXQgaXMgYSBnb29kIGlkZWEgdG8gaW5jbHVkZSB0aGlzIGluIG1vc3Qgb2YgeW91ciByZWNpcGVzIHdoZXJlIHlvdSBoYXZlIGEgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHdpdGggbWFueSBkaXN0aW5jdCB2YWx1ZXMuIFRoaXMgc3RlcCBuZWVkcyB0byBjb21lIGJlZm9yZSB3ZSBjcmVhdGUgZHVtbXkgdmFyaWFibGVzLiBIb3dldmVyLCB3ZSBhcmUgYWxzbyBjcmVhdGluZyBhIGR1bW15IHZhcmlhYmxlIGZyb20gdGhpcywgd2hpY2ggc3RpbGwgcmVzdWx0cyBpbiBhIHByb2JsZW0uIAoKCkxldCdzIG1vZGlmeSB0aGUgY2l0eSB2YXJpYWJsZSB0byBiZSB2YWx1ZXMgb2YgYGluIGEgY2l0eWAgb3IgYG5vdCBpbiBhIGNpdHlgIHVzaW5nIHRoZSBgaWZfZWxzZSgpYCBmdW5jdGlvbiBvZiBgZHBseXJgLiBBbHRlcm5hdGl2ZWx5IHlvdSBjb3VsZCBjcmVhdGUgYSBbY3VzdG9tIHN0ZXAgZnVuY3Rpb25dKGh0dHBzOi8vcmVjaXBlcy50aWR5bW9kZWxzLm9yZy9hcnRpY2xlcy9DdXN0b21fU3RlcHMuaHRtbCkgdG8gZG8gdGhpcyBhbmQgYWRkIHRoZSBzdGVwIGZ1bmN0aW9uIHRvIHlvdXIgcmVjaXBlLCBidXQgdGhhdCBpcyBiZXlvbmQgdGhlIHNjb3BlIG9mIHRoaXMgY2FzZSBzdHVkeS4gCgpXZSBuZWVkIHRvIGNyZWF0ZSBhIG5ldyByZWNpcGUgdG8gbW92ZSBmb3J3YXJkLCBhcyB0aGUgbGV2ZWxzIG9mIG91ciB2YXJpYWJsZXMgYXJlIGVzdGFibGlzaGVkIHRoZW4uIFdlIHdvdWxkIGFsc28gcG90ZW50aWFsbHkgaGF2ZSB0aGlzIGlzc3VlIGZvciBzdGF0ZSBhbmQgY291bnR5LiBTbyBsZXQncyBhbHNvIGRvIGEgc2ltaWxhciB0aGluZyBmb3IgYHN0YXRlYC4gVGhlIGBjb3VudHlgIHZhcmlhYmxlcyBhcHBlYXJzIHRvIGdldCBkcm9wcGVkIGR1ZSB0byBlaXRoZXIgY29ycmVsYXRpb24gb3IgbmVhciB6ZXJvIHZhcmlhbmNlLiBJdCBpcyBsaWtlbHkgZHVlIHRvIG5lYXIgemVybyB2YXJpYW5jZSBiZWNhdXNlIHRoaXMgaXMgdGhlIG1vcmUgZ3JhbnVsYXIgb2YgdGhlc2UgZ2VvZ3JhcGhpYyBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYW5kIGxpa2VseSBzcGFyc2UuCgoKYGBge3J9CgpwbVtbImNpdHkiXV08LWlmX2Vsc2UoCiAgcG1bWyJjaXR5Il1dID09ICJOb3QgaW4gYSBjaXR5IiwgCiAgdHJ1ZSA9ICJOb3QgaW4gYSBjaXR5IiwgZmFsc2UgPSAiSW4gYSBjaXR5IikKCnBtW1sic3RhdGUiXV0gPC0gaWZfZWxzZSgKICBwbVtbInN0YXRlIl1dID09ICJDYWxpZm9ybmlhIiwgCiAgdHJ1ZSA9ICJDYWxpZm9ybmlhIiwgZmFsc2UgPSAiTm90IENhbGlmb3JuaWEiKQoKc2V0LnNlZWQoMTIzNCkgIyBzYW1lIHNlZWQgYXMgYmVmb3JlCgpwbV9zcGxpdCA8LXJzYW1wbGU6OmluaXRpYWxfc3BsaXQoZGF0YSA9IHBtLCBwcm9wID0gMi8zKQpwbV9zcGxpdAogdHJhaW5fcG0gPC1yc2FtcGxlOjp0cmFpbmluZyhwbV9zcGxpdCkKIHRlc3RfcG0gPC1yc2FtcGxlOjp0ZXN0aW5nKHBtX3NwbGl0KQoKICAKbm92ZWxfcmVjIDwtcmVjaXBlKHRyYWluX3BtKSAlPiUKICAgIHVwZGF0ZV9yb2xlKGV2ZXJ5dGhpbmcoKSwgbmV3X3JvbGUgPSAicHJlZGljdG9yIiklPiUKICAgIHVwZGF0ZV9yb2xlKHZhbHVlLCBuZXdfcm9sZSA9ICJvdXRjb21lIiklPiUKICAgIHVwZGF0ZV9yb2xlKGlkLCBuZXdfcm9sZSA9ICJpZCB2YXJpYWJsZSIpJT4lCiAgICB1cGRhdGVfcm9sZSgiZmlwcyIsIG5ld19yb2xlID0gImNvdW50eSBpZCIpJT4lCiMgY3JlYXRlIG51bWVyaWMgZHVtbXkgdmFyaWFibGVzIHRvIGVuY29kZSBmb3IgY2F0ZWdvcmljYWwgdmFyaWFibGVzCiAgICBzdGVwX2R1bW15KHN0YXRlLCBjb3VudHksIGNpdHksIHpjdGEsIG9uZV9ob3QgPSBUUlVFKSAlPiUKIyBpZGVudGlmeSBhbmQgcmVvbXZlIGFsbCBjb3JyZWxhdGVkIHByZWRpY3RvcnMgKG5vdyB0aGF0IHRoZXkgYXJlIG51bWVyaWMpCiAgIHN0ZXBfY29ycihhbGxfbnVtZXJpYygpKSU+JQojIGlkZW50aWZ5IHZhcmlhYmxlcyB3aXRoIG5lYXIgemVybyB2YXJpYW5jZSBhbmQgcmVtb3ZlCiAgc3RlcF9uenYoYWxsX251bWVyaWMoKSkgIyAKIApgYGAKCk5vdyBsZXQncyByZXRyYWluIG91ciB0cmFpbmluZyBkYXRhIGFuZCB0cnkgYmFraW5nIG91ciB0ZXN0IGRhdGE6CgpgYGB7cn0KcHJlcHBlZF9yZWMgPC0gcHJlcChub3ZlbF9yZWMsIHZlcmJvc2UgPSBUUlVFLCByZXRhaW4gPSBUUlVFKQpgYGAKCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQojIFNjcm9sbCB0aGVyb3VnaCB0aGUgb3V0cHV0IQpqdWljZWRfdHJhaW48LSBqdWljZShwcmVwcGVkX3JlYykKZ2xpbXBzZShqdWljZWRfdHJhaW4pCmBgYAoKIyMjIwoKTm90aWNlLCBpdCBsb29rcyBsaWtlIHdlIGdhaW5lZCB0aGUgYGxvZ19wcmlzZWNfbGVuZ3RoXzI1MDAwYCBiYWNrIHdpdGggdGhpcyByZWNpcGUgdXNpbmcgdGhlIGRhdGEgd2l0aCBvdXIgY2hhbmdlcyB0byBgc3RhdGVgIGFuZCBgY2l0eWAuCgojIyMjIHsuc2Nyb2xsYWJsZSB9CgpgYGB7cn0KIyBTY3JvbGwgdGhlcm91Z2ggdGhlIG91dHB1dCEKYmFrZWRfdGVzdF9wbTwtIHJlY2lwZXM6OmJha2UocHJlcHBlZF9yZWMsIG5ld19kYXRhID0gdGVzdF9wbSkKZ2xpbXBzZShiYWtlZF90ZXN0X3BtKQpgYGAKCiMjIyMKCkdyZWF0IG5vdyB3ZSBubyBsb25nZXIgaGF2ZSBOQSB2YWx1ZXMhIDopCgoKTm90ZTogaWYgeW91IHVzZSB0aGUgc2tpcCBvcHRpb24gZm9yIHNvbWUgb2YgdGhlIHByZXByb2Nlc3Npbmcgc3RlcHMsIGJlIGNhcmVmdWwuIGBqdWljZSgpYCB3aWxsIHNob3cgYWxsIG9mIHRoZSByZXN1bHRzIGlnbm9yaW5nIGBza2lwID0gVFJVRWAuIGBiYWtlKClgIHdpbGwgbm90IG5lY2Vzc2FyaWx5IGNvbmR1Y3QgdGhlc2Ugc3RlcHMgb24gdGhlIG5ldyBkYXRhLiAKCgojIyMgU3BlY2lmeWluZyB0aGUgTW9kZWwKClNvIGZhciB3ZSBoYXZlIHVzZWQgYHJzYW1wbGVgIHRvIHNwbGl0IHRoZSBkYXRhIGFuZCBgcmVjaXBlc2AgdG8gYXNzaWduIHZhcmlhYmxlIGFuZCB0byBzcGVjaWZ5IGFuZCBwcmVwIG91ciBwcmVwcm9jZXNzaW5nIChhcyB3ZWxsIGFzIHRvIG9wdGlvbmFsbHkgZXh0cmFjdCB0aGUgcHJlcHJvY2Vzc2VkIGRhdGEpLgoKV2Ugd2lsbCBub3cgdXNlIHRoZSBgcGFyc25pcGAgcGFja2FnZSAod2hpY2ggaXMgc2ltaWxhciB0byB0aGUgcHJldmlvdXMgYGNhcmV0YCBwYWNrYWdlIC0gYW5kIGhlbmNlIHdoeSBpdCBpcyBuYW1lZCBhZnRlciB0aGUgdmVnZXRhYmxlKSB0byBzcGVjaWZ5IG91ciBtb2RlbC4KClRoZXJlIGFyZSBmb3VyIGFzcGVjdHMgdG8gZGVmaW5lIGFib3V0IG91ciBtb2RlbDogIAoxKSB0aGUgKip0eXBlKiogb2YgbW9kZWwgKHVzaW5nIHNwZWNpZmljIGZ1bmN0aW9ucyBpbiBwYXJzbmlwIGxpa2UgYHJhbmRfZm9yZXN0KClgLCBgbG9naXN0aWNfcmVnKClgIGV0Yy4pICAKMikgdGhlICoqbW9kZSoqIG9mIGxlYXJuaW5nIC0gY2xhc3NpZmljYXRpb24gb3IgcmVncmVzc2lvbiAodXNpbmcgdGhlIGBzZXRfbW9kZSgpYCBmdW5jdGlvbikgIAozKSB0aGUgcGFja2FnZSBvciAqKmVuZ2luZSoqIHRoYXQgd2Ugd2lsbCB1c2UgdG8gaW1wbGVtZW50IHRoZSB0eXBlIG9mIG1vZGVsIHNlbGVjdGVkICh1c2luZyB0aGUgYHNldF9lbmdpbmUoKWAgZnVuY3Rpb24pICAKNCkgYW55ICoqYXJndW1lbnRzKiogbmVjZXNzYXJ5IGZvciB0aGUgbW9kZWwvcGFja2FnZSBzZWxlY3RlZCAodXNpbmcgdGhlIGBzZXRfYXJncygpYGZ1bmN0aW9uIC0gIGZvciBleGFtcGxlIHRoZSBgbXRyeSA9YCBhcmd1bWVudCBmb3IgcmFuZG9tIGZvcmVzdCB3aGljaCBpcyB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcyB0byBiZSB1c2VkIGFzIG9wdGlvbnMgZm9yIHNwbGl0dGluZyBhdCBlYWNoIHRyZWUgbm9kZSkgIAoKV2UgYXJlIGdvaW5nIHRvIHN0YXJ0IG91ciBhbmFseXNpcyB3aXRoIGEgbGluZWFyIHJlZ3Jlc3Npb24gYnV0IHdlIHdpbGwgZGVtb25zdHJhdGUgaG93IHdlIGNhbiB0cnkgZGlmZmVyZW50IG1vZGVscy4KClRoZSBmaXJzdCB0aGluZyB3ZSBkbyBpcyBkZWZpbmUgd2hhdCB0eXBlIG9mIG1vZGVsIHdlIHdvdWxkIGxpa2UgdG8gdXNlLiBTZWUgW2hlcmVdKGh0dHBzOi8vdGlkeW1vZGVscy5naXRodWIuaW8vcGFyc25pcC9hcnRpY2xlcy9hcnRpY2xlcy9Nb2RlbHMuaHRtbAope3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vZGVsaW5nIFtvcHRpb25zXWluIHBhcnNuaXAuCgpgYGB7cn0KUE1fbW9kZWwgPC0gcGFyc25pcDo6bGluZWFyX3JlZygpICNQTSBmb3IgcGFydGljdWxhdGUgbWF0ZXIKUE1fbW9kZWwKYGBgCgpPSy4gU28gZmFyIGFsbCB3ZSBoYXZlIHRvbGQgYHBhcnNuaXBgIGlzIHdlIHdhbnQgdG8gdXNlIGEgbGluZWFyIHJlZ3Jlc3Npb24uLi4gIExldCdzIHRlbGwgYHBhcnNuaXBgIG1vcmUgYWJvdXQgd2hhdCB3ZSB3YW50LgoKV2Ugd291bGQgbGlrZSB0byB1c2UgdGhlIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgbWV0aG9kIHRvIGZpdCBvdXIgbGluZWFyIHJlZ3Jlc3Npb24uIFNvIHdlIHdpbGwgdGVsbCBgcGFyc25pcGAgdGhhdCB3ZSB3YW50IHRvIHVzZSB0aGUgYGxtYCBwYWNrYWdlIHRvIGltcGxlbWVudCBvdXIgbGluZWFyIHJlZ3Jlc3Npb24gKHRoZXJlIGFyZSBtYW55IG9wdGlvbnMgYWN0dWFsbHktIHN1Y2ggYXMgW2Byc3RhbmBdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yc3Rhbi92aWduZXR0ZXMvcnN0YW4uaHRtbCkgW2BnbG1uZXRgXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2xtbmV0L2luZGV4Lmh0bWwpLCBbYGtlcmFzYF0oaHR0cHM6Ly9rZXJhcy5yc3R1ZGlvLmNvbS8pLCBhbmQgW2BzcGFya2x5cmBdKGh0dHBzOi8vdGhlcmluc3BhcmsuY29tL3N0YXJ0aW5nLmh0bWwjc3RhcnRpbmctc3BhcmtseXItaGVsbG8td29ybGQpKS4gV2Ugd2lsbCBkbyBzbyBieSB1c2luZyB0aGUgYHNldF9lbmdpbmUoKWAgZnVuY3Rpb24gb2YgdGhlIGBwYXJzbmlwYCBwYWNrYWdlLgoKYGBge3J9CmxtX1BNX21vZGVsIDwtIAogIFBNX21vZGVsICAlPiUKICBwYXJzbmlwOjpzZXRfZW5naW5lKCJsbSIpCgpsbV9QTV9tb2RlbAoKYGBgCgpJbiBzb21lIGNhc2VzIHNvbWUgcGFja2FnZXMgY2FuIGRvIGVpdGhlciBjbGFzc2lmaWNhdGlvbiBvciBwcmVkaWN0aW9uLCBzbyBpdCBpcyBhIGdvb2QgaWRlYSB0byBzcGVjaWZ5IHdoaWNoIG1vZGUgeW91IGludGVuZCB0byBwZXJmb3JtLiBZb3UgY2FuIGRvIHRoaXMgd2l0aCB0aGUgYHNldF9tb2RlKClgIGZ1bmN0aW9uIG9mIHRoZSBgcGFyc25pcGAgcGFja2FnZSwgYnkgdXNpbmcgZWl0aGVyIGBzZXRfbW9kZSgiY2xhc3NpZmljYXRpb24iKWAgb3IgYHNldF9tb2RlKCJyZWdyZXNzaW9uIilgLgoKYGBge3J9CmxtX1BNX21vZGVsIDwtIAogIFBNX21vZGVsICAlPiUKICBwYXJzbmlwOjpzZXRfZW5naW5lKCJsbSIpICU+JQogIHNldF9tb2RlKCJyZWdyZXNzaW9uIikKCmxtX1BNX21vZGVsCgpgYGAKCiMjIyBGaXR0aW5nIHRoZSBNb2RlbDogdHdvIHdheXMgLSBgd29ya2Zsb3dzYCBhbmQgYHBhcnNuaXBgCgpUbyBmaXQgb3VyIG1vZGVsIHdlIGNhbiB1c2UgdGhlIGBwYXJzbmlwYCBwYWNrYWdlIGFuZCB0aGVuIGFzc2VzcyBvdXIgZml0IHVzaW5nIHRoZSBgeWFyZHN0aWNrYCBwYWNrYWdlLgoKSG93ZXZlciBhIG5ld2VyIHBhY2thZ2UgY2FsbGVkIGB3b3JrZmxvd3NgIGFsbG93cyB1cyB0byBrZWVwIHRyYWNrIG9mIGJvdGggb3VyIHByZXByb2Nlc3Npbmcgc3RlcHMgYW5kIG91ciBtb2RlbCBzcGVjaWZpY2F0aW9uLiBJdCBhbHNvIGFsbG93cyB1cyB0byBpbXBsZW1lbnQgZmFuY2llciBvcHRpbWl6YXRpb25zIGluIGFuIGF1dG9tYXRlZCB3YXkgYW5kIGl0IGlzIGN1cnJlbnRseSBiZWluZyBkZXZlbG9wZWQgdG8gYWxzbyBoYW5kbGUgcG9zdC1wcm9jZXNzaW5nIG9wZXJhdGlvbnMsIHNvIGl0IGlzIGdvb2QgdG8gbGVhcm4gYWJvdXQgaXQhCgpTbyB3ZSB3aWxsIG5vdyBjcmVhdGUgYSB3b3JrZmxvdyB3aXRoIHRoZSByZWNpcGUgKG91ciBwcmVwcm9jZXNzaW5nIHNwZWNpZmljYXRpb25zKSB0aGF0IHdlIG1hZGUgYW5kIHRoZSBtb2RlbCB0aGF0IHdlIGp1c3Qgc3BlY2lmaWVkLgoKRmlyc3Qgd2UgdXNlIHRoZSBgd29ya2Zsb3coKWAgZnVuY3Rpb24gb2YgdGhlIGB3b3JrZmxvd3NgIHBhY2thZ2UgdG8gY3JlYXRlIGEgd29ya2Zsb3cuCgpUaGVuIHdlIGFkZCBvdXIgcmVjaXBlIHdpdGggdGhlIGBhZGRfcmVjaXBlKClgIGZ1bmN0aW9uIGFuZCB3ZSBhZGQgb3VyIG1vZGVsIHdpdGggdGhlIGBhZGRfbW9kZWwoKWAgZnVuY3Rpb24gb2YgdGhlIGB3b3JrZmxvd3NgIHBhY2thZ2UuIAoKTm90ZTogV2UgZG8gbm90IG5lZWQgdG8gYWN0dWFsbHkgcHJlcCBvdXIgcmVjaXBlIGJlZm9yZSB1c2luZyB3b3JrZmxvd3MhCgpgYGB7cn0KUE1fd2Zsb3cgPC13b3JrZmxvd3M6OndvcmtmbG93KCkgJT4lCiAgICAgICAgICAgd29ya2Zsb3dzOjphZGRfcmVjaXBlKG5vdmVsX3JlYykgJT4lCiAgICAgICAgICAgd29ya2Zsb3dzOjphZGRfbW9kZWwobG1fUE1fbW9kZWwpClBNX3dmbG93CmBgYAoKQWgsIG5pY2UuIE5vdGljZSBob3cgaXQgdGVsbHMgdXMgYWJvdXQgYm90aCBvdXIgcHJlcHJvY2Vzc2luZyBzdGVwcyBhbmQgb3VyIG1vZGVsIHNwZWNpZmljYXRpb25zLgoKTm93IHdlIGNhbiBwcmVwYXJlIHRoZSByZWNpcGUgKGVzdGltYXRlIHRoZSBwYXJhbWV0ZXJzKSBhbmQgZml0IHRoZSBtb2RlbCB0byBvdXIgdHJhaW5pbmcgZGF0YSBhbGwgYXQgb25jZS4gUHJpbnRpbmcgdGhlIG91dHB1dCB3ZSBjYW4gc2VlIHRoZSBjb2VmZmljaWVudHMgb2YgdGhlIG1vZGVsLgoKYGBge3J9ClBNX3dmbG93X2ZpdCA8LSBwYXJzbmlwOjpmaXQoUE1fd2Zsb3csIGRhdGEgPSB0cmFpbl9wbSkKUE1fd2Zsb3dfZml0CmBgYAoKT3RoZXJ3aXNlIHdlIGNvdWxkIGhhdmUgZG9uZSB0aGlzIHdpdGhvdXQgdGhlIGB3b3JrZmxvd3NgIHBhY2thZ2UuIE5vdGljZSBoZXJlIHdlIHdpbGwgdXNlZCB0aGUgcHJvY2Vzc2VkIHRyYWluaW5nIGRhdGEgKGBqdWljZWRfdHJhaW5gKSBhcyBvcHBvc2VkIHRvIHRoZSByYXcgdHJhaW5pbmcgZGF0YSB0aGF0IHdlIHVzZWQgd2l0aCB0aGUgd29ya2Zsb3cgd2UgY3JlYXRlZCB3aXRoIGB3b3JrZmxvd3NgLgoKSW4gdGhpcyBjYXNlLCB3ZSBhY3R1YWxseSBuZWVkIHRvIHdyaXRlIHlvdXIgbW9kZWwgYWdhaW4hIFJlY2FsbCB0aGF0IGBpZGAgYW5kIGBmaXBzYCBhcmUgSUQgdmFyaWFibGVzIGFuZCB0aGF0IGB2YWx1ZXNgIGlzIG91ciBvdXRjb21lIG9mIGludGVyZXN0ICh0aGUgcG0gYWlyIHBvbGx1dGlvbiBtZWFzdXJlIGF0IGVhY2ggbW9uaXRvcikuIAoKYGBge3J9Cmp1aWNlZF90cmFpbl9yZWFkeSA8LSBqdWljZWRfdHJhaW4lPiUgc2VsZWN0KCAtaWQsIC1maXBzKQpQTV9maXQgPC0gbG1fUE1fbW9kZWwgJT4lIApwYXJzbmlwOjpmaXQodmFsdWUgfi4sIGRhdGEgPWp1aWNlZF90cmFpbl9yZWFkeSkKCmBgYAoKIyMjIExvb2tpbmcgYXQgbW9kZWwgZml0IHdpdGggYGJyb29tYAoKVGhlIGBicm9vbWAgcGFja2FnZSBhbGxvd3MgZm9yIGFuIGVhc3kvdGlkeSB3YXkgdG8gbG9vayBhdCB0aGUgZml0dGVkIG1vZGVsOiAgCgpgdGlkeSgpYCBncmFicyB0aGUgY29lZmZpY2llbnRzIGZyb20gdGhlIG1vZGVsICAKYGdsYW5jZSgpYCBzdW1tYXJpemVzIHRoZSBtb2RlbCBmaXQgYW5kIGdpdmVzIHVzIGFuIGlkZWEgYWJvdXQgaG93IHdlbGwgdGhlIG1vZGVsIG1pZ2h0IHBlcmZvcm0KYGF1Z21lbnQoKWAgZ2l2ZXMgYSAxNTAgcm93IG9ic2VydmF0aW9uIGxldmVsIHN1bW1hcnkgb2YgdGhlIGRhdGEgYW5kIGZpdCAKClRoZXNlIGBicm9vbWAgZnVuY3Rpb25zIGN1cnJlbnRseSBvbmx5IHdvcmsgd2l0aCBgcGFyc25pcGAgb2JqZWN0cyBub3QgcmF3IGB3b3JrZmxvd3NgIG9iamVjdHMuIFRvIHVzZSB0aGUgYHRpZHkoKWAgZnVuY3Rpb24gd2l0aCBgd29ya2Zsb3dzYCB3ZSBuZWVkIHRvIGZpcnN0IHVzZSB0aGUgYHB1bGxfd29ya2Zsb3dfZml0KClgIGZ1bmN0aW9uLgoKYGBge3J9CmJyb29tOjp0aWR5KFBNX2ZpdCkgJT4lIGFycmFuZ2UocC52YWx1ZSkKYnJvb206OmdsYW5jZShQTV9maXRbWyJmaXQiXV0pCmJyb29tOjphdWdtZW50KFBNX2ZpdFtbImZpdCJdXSkgIyB0aGlzIGFsc28gZ2l2ZXMgdXMgdGhlIGZpdHRlZCB2YWx1ZXMsIHN0YW5kYXJkIGVycm9yIGZvciBlYWNoIGFuZCBtb3JlIQoKCndmbG93b3V0cHV0PC1QTV93Zmxvd19maXQgJT4lIAogIHB1bGxfd29ya2Zsb3dfZml0KCkgJT4lIAogIGJyb29tOjp0aWR5KCkgCgoKI1RoZSBvdXRwdXQgaXMgaWRlbnRpY2FsIHVzaW5nIHdvcmtmbG93cyB0byBmaXQgdGhlIG1vZGVsIG9yIGp1c3QgcGFyc25pcAppZGVudGljYWwodGlkeShQTV9maXQpLCB3Zmxvd291dHB1dCkKCmBgYAoKCk9LLCBzbyB3ZSBoYXZlIGZpdCBvdXIgbW9kZWwgb24gb3VyIHRyYWluaW5nIGRhdGEsIHdoaWNoIG1lYW5zIHdlIGhhdmUgY3JlYXRlZCBhIG1vZGVsIHRvIHByZWRpY3QgdmFsdWVzIG9mIGFpciBwb2xsdXRpb24gYmFzZWQgb24gdGhlIHByZWRpY3RvcnMgdGhhdCB3ZSBoYXZlIGluY2x1ZGVkLiBZYXkhCgoKV2UgY2FuIGdldCBhIHNlbnNlIG9mIHRoZSB2YXJpYWJsZSBpbXBvcnRhbmNlIHVzaW5nIHRoZSBgdmlwKClgIGZ1bmN0aW9uIG9mIHRoZSBgdmlwYCBwYWNrYWdlLiAKCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSB0b3AgMTAgY29udHJpYnV0aW5nIHZhcmlhYmxlczoKCmBgYHtyfQpQTV93Zmxvd19maXQgJT4lIAogIHB1bGxfd29ya2Zsb3dfZml0KCkgJT4lIAogIHZpcChudW1fZmVhdHVyZXMgPSAxMCkKYGBgCgojIyMgTW9kZWwgUGVyZm9ybWFuY2UKCkxldCdzIHRha2UgYSBsb29rIGF0IGhvdyB3ZWxsIG91ciBtb2RlbCBmaXQgb3VyIHRyYWluaW5nIGRhdGE6CgoKYGBge3J9CiMjdXNpbmcgdGhlIHBhcnNuaXAgdmVyc2lvbgojY2FuIGdyYWIgdGhlIGZpdHRlZCB2YWx1ZXMgc2ltcGx5IGxpa2UgdGhpczoKcGFyc25pcF9maXR0ZWRfdmFsdWVzPC1maXR0ZWQoUE1fZml0W1siZml0Il1dKQoKaGVhZChwYXJzbmlwX2ZpdHRlZF92YWx1ZXMpCgojY2FuIGFsc28gZ2V0IHRoZSB2YWx1ZXMgdXNpbmcgdGhlIGF1Z21lbnQgZnVuY3Rpb24KcGFyc25pcF9maXR0ZWRfdmFsdWVzIDwtIGF1Z21lbnQoUE1fZml0W1siZml0Il1dLCBkYXRhID0ganVpY2VkX3RyYWluKSAlPiUgCnNlbGVjdCh2YWx1ZSwgLmZpdHRlZDouc3RkLnJlc2lkKQoKaGVhZChwYXJzbmlwX2ZpdHRlZF92YWx1ZXMpCgojI3VzaW5nIHRoZSB3b3JrZmxvd3MgdmVyc2lvbgp3Zl9maXQgPC1QTV93Zmxvd19maXQgJT4lIAogIHB1bGxfd29ya2Zsb3dfZml0KCkKCiNjYW4gZ3JhYiB0aGUgZml0dGVkIHZhbHVlcyBzaW1wbHkgbGlrZSB0aGlzOgp3Zl9maXR0ZWRfdmFsdWVzPC1maXR0ZWQod2ZfZml0W1siZml0Il1dKQoKaGVhZCh3Zl9maXR0ZWRfdmFsdWVzKQoKI2NhbiBhbHNvIGdldCB0aGUgdmFsdWVzIHVzaW5nIHRoZSBhdWdtZW50IGZ1bmN0aW9uCndmX2ZpdHRlZF92YWx1ZXMgPC1hdWdtZW50KHdmX2ZpdFtbImZpdCJdXSwgZGF0YSA9IGp1aWNlZF90cmFpbikgJT4lIApzZWxlY3QodmFsdWUsIC5maXR0ZWQ6LnN0ZC5yZXNpZCkKCmhlYWQod2ZfZml0dGVkX3ZhbHVlcykKCiNnaXZlcyB1cyB0aGUgc2FtZSBmaXR0ZWQgdmFsdWVzCmlkZW50aWNhbChwYXJzbmlwX2ZpdHRlZF92YWx1ZXMsIHdmX2ZpdHRlZF92YWx1ZXMpCgojIyBMZXQncyBtYWtlIGEgcGxvdCBvZiBmaXR0ZWQgYW5kIHJlYWwgdmFsdWVzCgpnZ3Bsb3Qod2ZfZml0dGVkX3ZhbHVlcywgYWVzKHggPSAuZml0dGVkLCB5ID0gdmFsdWUpKSArIGdlb21fcG9pbnQoKQpgYGAKCk9LLCBzbyBvdXIgZml0dGVkIHJhbmdlIGFwcGVhcnMgdG8gYmUgc21hbGxlciB0aGFuIHRoZSByZWFsIHZhbHVlcy4gV2UgY291bGQgcHJvYmFibHkgZG8gYSBiaXQgYmV0dGVyLgoKCkxldCdzIHRha2UgYSBsb29rIGF0IGhvdyB3ZWxsIG91ciBtb2RlbCBzZWVtcyB0byBiZSBwcmVmb3JtaW5nIG1vcmUgZm9ybWFsbHk6CgpXaGVuIGFzc2Vzc2luZyB0aGUgcGVyZm9ybWFuY2Ugb2YgYSBtb2RlbCwgdGhlIG1ldHJpY3Mgd2UgdXNlIGRlcGVuZCBvbiBpZiB3ZSBhcmUgcHJlZm9ybWluZyBhIGNsYXNzaWZpY2F0aW9uIG9yIHByZWRpY3Rpb24gYWxzbyBrbm93biBhcyByZWdyZXNzaW9uIGFuYWx5c2lzLiBJbiBvdXIgY2FzZSB3ZSBhcmUgcGVyZm9ybWluZyBhIHJlZ3Jlc3Npb24gb3IgcHJlZGljdGlvbiBhbmFseXNpcyBhbmQgdGhlIG1ldHJpY3Mgb2Z0ZW4gdXNlZCBhcmU6CjEpIG1lYW4gYWJzb2x1dGUgZXJyb3IgKG1hZSkgIAoyKSBSIHNxdWFyZWQgZXJyb3IgKHJzcSkgClRoaXMgaXMgYWxzbyBrbm93biBhcyB0aGUgY29lZmZpY2llbnQgb2YgZGV0ZXJtaW5hdGlvbiB3aGljaCBpcyB0aGUgc3F1YXJlZCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRydXRoIGFuZCBlc3RpbWF0ZSAgCjMpIHJvb3QgbWVhbiBzcXVhcmVkIGVycm9yIChybXNlKSAgIAoKCldlIGNhbiB1c2UgdGhlIGB5YXJkc3RpY2tgIHBhY2thZ2UgdG8gcXVpY2tseSBjYWxjdWxhdGUgZXN0aW1hdGVzIGZvciBhbGwgb2YgdGhlc2UgdmFsdWVzIHVzaW5nIHRoZSBgbWV0cmljcygpYCBmdW5jdGlvbi4gQWx0ZXJuYXRpdmVseSBpZiB5b3Ugb25seSB3YW50ZWQgb25lIG1ldHJpYyB5b3UgY291bGQgdXNlIHRoZSBgbWFlKClgLCBgcnNxKClgLCBvciBgcm1zZSgpYCBmdW5jdGlvbnMgcmVzcGVjdGl2ZWx5LiBUaGlzIGlzIGhlbHBmdWwgdG8gZXhhbWluZSB3aXRoIG91ciBmaXR0ZWQgdHJhaW5pbmcgc2V0IHZhbHVlcyB0byBzZWUgaG93IHdlbGwgb3VyIG1vZGVsIGlzIHBlcmZvcm1pbmcgYW5kIGlmIHdlIG5lZWQgdG8gbWFrZSBhZGp1c3RtZW50cy4gCgpgYGB7cn0KCnlhcmRzdGljazo6bWV0cmljcyh3Zl9maXR0ZWRfdmFsdWVzLCB0cnV0aCA9IHZhbHVlLCBlc3RpbWF0ZSA9IC5maXR0ZWQpCnlhcmRzdGljazo6bWFlKHdmX2ZpdHRlZF92YWx1ZXMsIHRydXRoID0gdmFsdWUsIGVzdGltYXRlID0gLmZpdHRlZCkKCmBgYAoKCiMjIyBDcm9zcyB2YWxpZGF0aW9uIHNhbXBsZSBzcGxpdHRpbmcKCldlIHdpbGwgdXNlIHRoZSBgcnNhbXBsZWAgcGFja2FnZSBhZ2FpbiBpbiBvcmRlciB0byBmdXJ0aGVyIGltcGxlbWVudCB3aGF0IGFyZSBjYWxsZWQgW2Nyb3NzIHZhbGlkYXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLXZhbGlkYXRpb25fKHN0YXRpc3RpY3MpKXt0YXJnZXQ9Il9ibGFuayJ9IHRlY2huaXF1ZXMuIFRoaXMgaXMgYWxzbyBjYWxsZWQgKipyZXNhbXBsaW5nKiogb3IgKipyZXBhcnRpb25pbmcqKi4gIAoKTm90ZTogd2UgYXJlIG5vdCBhY3R1YWxseSBnZXR0aW5nIG5ldyBzYW1wbGVzIGZyb20gdGhlIHVuZGVybHlpbmcgZGlzdHJpYnV0aW9uIHNvIHRoZSB0ZXJtIHJlc2FtcGxpbmcgaXMgYSBiaXQgb2YgYSBtaXNub21lci4KCltDcm9zcyB2YWxpZGF0aW9uXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Dcm9zcy12YWxpZGF0aW9uXyhzdGF0aXN0aWNzKSl7dGFyZ2V0PSJfYmxhbmsifSBzcGxpdHMgb3VyIHRyYWluaW5nIGRhdGEgaW50byBtdWx0aXBsZSB0cmFpbmluZyBkYXRhIHNldHMgdG8gYWxsb3cgZm9yIGEgZGVlcGVyIGFzc2Vzc21lbnQgb2YgdGhlIGFjY3VyYWN5IG9mIHRoZSBtb2RlbC4KCkhlcmUgaXMgYSB2aXN1YWxpemF0aW9uIG9mIHRoZSBjb25jZXB0IGZvciBjcm9zcyB2YWxpZGF0aW9uL3Jlc2FtcGxpbmcvcmVwYXJ0aXRpb25pbmcgZnJvbSBbTWF4IEt1aG5dKGh0dHBzOi8vcmVzb3VyY2VzLnJzdHVkaW8uY29tL2F1dGhvcnMvbWF4LWt1aG4pe3RhcmdldD0iX2JsYW5rIn06CgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI4MDBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsInJlc2FtcGxpbmcucG5nIikpCmBgYAoKVGVjaG5pY2FsbHkgY3JlYXRpbmcgb3VyIHRlc3RpbmcgYW5kIHRyYWluaW5nIHNldCBvdXQgb2Ygb3VyIG9yaWdpbmFsIHRyYWluaW5nIGRhdGEgaXMgc29tZXRpbWVzIGNvbnNpZGVyZWQgYSBmb3JtIG9mIFtjcm9zcyB2YWxpZGF0aW9uXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Dcm9zcy12YWxpZGF0aW9uXyhzdGF0aXN0aWNzKSl7dGFyZ2V0PSJfYmxhbmsifSBjYWxsZWQgdGhlIGhvbGRvdXQgbWV0aG9kLiBBcyB3ZSBqdXN0IGxlYXJuZWQgdGhpcyBjYW4gZ2l2ZSB1cyBhIGJldHRlciBzZW5zZSBvZiB0aGUgYWNjdXJhY3kgb2Ygb3VyIGRhdGEgaW4gYSBtb3JlIGdlbmVyYWxpemFibGUgd2F5LiAKCkhvd2V2ZXIsIHdlIGNhbiBkbyBhIGJldHRlciBqb2Igb2Ygb3B0aW1pemluZyBvdXIgbW9kZWwgZm9yIGFjY3VyYWN5IGlmIHdlIGFsc28gcGVyZm9ybSBhbm90aGVyIHR5cGUgb2YgW2Nyb3NzIHZhbGlkYXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLXZhbGlkYXRpb25fKHN0YXRpc3RpY3MpKXt0YXJnZXQ9Il9ibGFuayJ9IG9uIHRoZSBuZXdseSBkZWZpbmVkIHRyYWluaW5nIHNldCB0aGF0IHdlIGp1c3QgY3JlYXRlZC4gVGhlcmUgYXJlIG1hbnkgW2Nyb3NzIHZhbGlkYXRpb25dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLXZhbGlkYXRpb25fKHN0YXRpc3RpY3MpKXt0YXJnZXQ9Il9ibGFuayJ9IG1ldGhvZHMgYW5kIG1vc3QgY2FuIGJlIGVhc2lseSBpbXBsZW1lbnRlZCB1c2luZyBgcnNhbXBsZXNgIHBhY2thZ2UuIFdlIHdpbGwgdXNlIGEgdmVyeSBwb3B1bGFyIG1ldGhvZCBjYWxsZWQgZWl0aGVyIFtrLWZvbGQgb3Igdi1mb2xkIGNyb3NzIHZhbGlkYXRpb25dKGh0dHBzOi8vbWFjaGluZWxlYXJuaW5nbWFzdGVyeS5jb20vay1mb2xkLWNyb3NzLXZhbGlkYXRpb24vKXt0YXJnZXQ9Il9ibGFuayJ9LiAKClRoaXMgbWV0aG9kIGludm9sdmVzIGVzc2VudGlhbGx5IHByZWZvcm1pbmcgdGhlIGhvbGQgb3V0IG1ldGhvZCBpdGVyYXRpdmVseSB3aXRoIHRoZSB0cmFpbmluZyBkYXRhLiAKCkZpcnN0IHRoZSB0cmFpbmluZyBzZXQgaXMgZGl2aWRlZCBpbnRvIGsgb3IgdiBlcXVhbGx5IHNpemVkIHNtYWxsZXIgcGllY2VzLiAKClRoZW4gdGhlIG1vZGVsIGlzIHRyYWluZWQgb24gdGhlIG1vZGVsIG9uIGstMSBvciB2LTEgc3Vic2V0cyBvZiB0aGUgZGF0YSBpdGVyYXRpdmVseSAocmVtb3ZpbmcgYSBkaWZmZXJlbnQgdiBvciBrIHVudGlsIGFsbCBwb3NzaWJsZSBrLTEgb3Igdi0xIHNldHMgaGF2ZSBiZWVuIGV2YWx1YXRlZCkgdG8gZ2V0IGEgc2Vuc2Ugb2YgdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbC4gVGhpcyBpcyByZWFsbHkgdXNlZnVsIGZvciBmaW5lIHR1bmluZyBzcGVjaWZpYyBhc3BlY3RzIG9mIHRoZSBtb2RlbCBpbiBhIHByb2Nlc3MgY2FsbGVkIG1vZGVsIHR1bmluZy4KCgpIZXJlIGlzIGEgdmlzdWFsaXphdGlvbiBvZiBob3cgdGhlIGZvbGRzIGFyZSBjcmVhdGVkOgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJ2Zm9sZC5wbmciKSkKYGBgCgoKTm90ZTogUGVvcGxlIHR5cGljYWxseSBpZ25vcmUgc3BhdGlhbCBkZXBlbmRlbmNlIHdpdGggY3Jvc3MgdmFsaWRhdGlvbiBvZiBhaXIgcG9sbHV0aW9uIG1vbml0b3JpbmcgZGF0YSBpbiB0aGUgYWlyIHBvbGx1dGlvbiBmaWVsZCwgc28gd2Ugd2lsbCBkbyB0aGUgc2FtZS4gIEhvd2V2ZXIsIGl0IG1pZ2h0IG1ha2Ugc2Vuc2UgdG8gbGVhdmUgb3V0IGJsb2NrcyBvZiBtb25pdG9ycyByYXRoZXIgdGhhbiAgcmFuZG9tIGluZGl2aWR1YWwgbW9uaXRvcnMgdG8gaGVscCBhY2NvdW50IGZvciBzb21lIHNwYXRpYWwgZGVwZW5kZW5jZS4KClRoZSBbYHZmb2xkX2N2KClgXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3JzYW1wbGUvcmVmZXJlbmNlL3Zmb2xkX2N2Lmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gZnVuY3Rpb24gb2YgdGhlIGByc2FtcGxlYCBwYWNrYWdlIGNhbiBiZSB1c2VkIHRvIHBhcnNlIHRoZSB0cmFpbmluZyBkYXRhIGludG8gZm9sZHMgZm9yIGstZm9sZC92LWZvbGQgY3Jvc3MgdmFsaWRhdGlvbi4KClRoZSBgdmAgYXJndW1lbnQgc3BlY2lmaWVzIHRoZSBudW1iZXIgb2YgZm9sZHMgdG8gY3JlYXRlLgpUaGUgYHJlcGVhdHNgIGFyZ3VtZW50IHNwZWNpZmllcyBpZiBhbnkgc2FtcGxlcyBzaG91bGQgYmUgcmVwZWF0ZWQgYWNyb3NzIGZvbGRzIC0gZGVmYXVsdCBpcyBgRkFMU0VgClRoZSBgc3RyYXRhYCBhcmd1bWVudCBzcGVjaWZpZXMgYSB2YXJpYWJsZSB0byBzdHJhdGlmeSBzYW1wbGVzIGFjcm9zcyBmb2xkcyAoanVzdCBsaWtlIGluIGBpbml0aWFsX3NwbGl0KClgKS4KCkFnYWluIGJlY2F1c2UgdGhlc2UgYXJlIGNyZWF0ZWQgYXQgcmFuZG9tLCB3ZSBuZWVkIHRvIHVzZSB0aGUgYmFzZSBgc2V0LnNlZWQoKWAgZnVuY3Rpb24gaW4gb3JkZXIgdG8gb2J0YWluIHRoZSBzYW1lIHJlc3VsdHMgZWFjaCB0aW1lIHdlIGtuaXQgdGhpcyBkb2N1bWVudC4gR2VuZXJhbGx5IHNwZWFraW5nIHVzaW5nIDEwIGZvbGRzIGlzIGdvb2QgcHJhY3RpY2UsIGJ1dCB0aGlzIGRlcGVuZHMgb24gdGhlIHZhcmlhYmxpdHkgd2l0aGluIHlvdXIgZGF0YS4gV2UgYXJlIGdvaW5nIHRvIHVzZSA0IGZvciB0aGUgc2FrZSBvZiBleHBlZGllbmN5LiAKCmBgYHtyfQpzZXQuc2VlZCgxMjM0KQoKdmZvbGRfcG0gPC1yc2FtcGxlOjp2Zm9sZF9jdihkYXRhID0gdHJhaW5fcG0sIHYgPSA0KQoKdmZvbGRfcG0KCgp2Zm9sZF9wbSRzcGxpdHMkYDFgCnZmb2xkX3BtJHNwbGl0cyRgMmAKYGBgCgpPbmNlIHRoZSBmb2xkcyBhcmUgY3JlYXRlZCB0aGV5IGNhbiBiZSB1c2VkIHRvIGV2YWx1YXRlIHBlcmZvcm1hbmNlIGJ5IGZpdHRpbmcgdGhlIG1vZGVsIHRvIGVhY2ggb2YgdGhlIHJlc2FtcGxlcyB0aGF0IHdlIGNyZWF0ZWQ6CgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJjcm9zc192YWxpZGF0aW9uLnBuZyIpKQpgYGAKCgpXZSBjYW4gZml0IHRoZSBtb2RlbCB0byBvdXIgY3Jvc3MgdmFsaWRhdGlvbiBmb2xkcyB1c2luZyB0aGUgYGZpdF9yZXNhbXBsZXMoKWAgZnVuY3Rpb24gb2YgdGhlIGB0dW5lYCBwYWNrYWdlLCBieSBzcGVjaWZ5aW5nIG91ciB3b3JrZmxvdyBvYmplY3QgYW5kIHRoZSBjcm9zcyB2YWxpZGF0aW9uIGZvbGQgb2JqZWN0IHdlIGp1c3QgY3JlYXRlZC4gU2VlIFtoZXJlXShodHRwczovL3RpZHltb2RlbHMuZ2l0aHViLmlvL3R1bmUvcmVmZXJlbmNlL2ZpdF9yZXNhbXBsZXMuaHRtbCkgZm9yIG1vcmUgaW5mb3JtYXRpb24uCgpgYGB7cn0KY29udHJvbCA8LSBjb250cm9sX3Jlc2FtcGxlcyhzYXZlX3ByZWQgPSBUUlVFKQpyZXNhbXBsZV9maXQgPC10dW5lOjpmaXRfcmVzYW1wbGVzKFBNX3dmbG93LCB2Zm9sZF9wbSkKCmBgYAoKV2UgY2FuIG5vdyB0YWtlIGEgbG9vayBhdCB2YXJpb3VzIG1ldHJpY3Mgb2YgcGVyZm9ybWFuY2UgYmFzZWQgb24gdGhlIGZpdCBvZiBvdXIgY3Jvc3MgdmFsaWRhdGlvbiAicmVzYW1wbGVzIi4gVG8gZG8gdGhpcyB3ZSB3aWxsIHVzZSB0aGUgYHNob3dfYmVzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHR1bmVgIHBhY2thZ2UuCgpgYGB7cn0KdHVuZTo6c2hvd19iZXN0KHJlc2FtcGxlX2ZpdCwgbWV0cmljID0gInJtc2UiLCAicnNxIikKYGBgCgoKIyMjIFR1bmluZwoKTm93IGxldCdzIHRyeSBzb21lIHR1bmluZy4KCkxldCdzIHRha2UgYSBjbG9zZXIgbG9vayBhdCBob3cgdGhlIGFpciBwb2xsdXRpb24gbW9uaXRvciB2YWx1ZXMgdmFyeSB3aXRoIHRoZSBsb2NhdGlvbiBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlLgoKYGBge3J9Cgp0cmFpbl9wbSAlPiUgCiAgZHBseXI6OnNlbGVjdCh2YWx1ZSwgbG9uLCBsYXQpICU+JSAKICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGxvbiwgbGF0KSwgCiAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJwcmVkaWN0b3IiLCB2YWx1ZXNfdG8gPSAibG9jX3ZhbHVlIikgJT4lIAogIGdncGxvdChhZXMoeCA9IGxvY192YWx1ZSwgdmFsdWUpKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAuMikgKyAKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKSArIAogICNzY2FsZV95X2xvZzEwKCkgKwogIGZhY2V0X3dyYXAofiBwcmVkaWN0b3IsIHNjYWxlcyA9ICJmcmVlX3giKQpgYGAKCldlIGNhbiBzZWUgdGhhdCB0aGVyZSBkb2VzIG5vdCBhcHBlYXIgdG8gYmUgYSBzaW5nbGUgbGluZWFyIHJlbGF0aW9uc2hpcCBmb3IgZWl0aGVyIG9mIHRoZXNlIHByZWRpY3RvcnMuIFRodXMgd2UgbWlnaHQgd2FudCB0byB0aGluayBhYm91dCB1c2luZyAgW3NwbGluZXNdKGh0dHBzOi8vd3d3Lm1hdGgudWguZWR1L35qaW5ncWl1L21hdGg0MzY0L3NwbGluZS5wZGYpIG9yIHRoaXMoaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL251bWVyaWNhbC1pbnRlcnBvbGF0aW9uLW5hdHVyYWwtY3ViaWMtc3BsaW5lLTUyYzExNTdiOThhYykgb3IganVzdCB0aGlzKGh0dHBzOi8vdGlkeW1vZGVscy5naXRodWIuaW8vdHVuZS9hcnRpY2xlcy9nZXR0aW5nX3N0YXJ0ZWQuaHRtbCkgb3IgdGhpcyhodHRwczovL3d3dy5wc3ljaC5tY2dpbGwuY2EvbWlzYy9mZGEvZXgtYmFzaXMtYjEuaHRtbCkgdG8gbW9kZWwgdGhlIHJlbGF0aW9uc2hpcCBpbiBvdXIgdHJhaW5pbmcgZGF0YSBtb3JlIGNsb3NlbHkuIEZvciBleGFtcGxlIGZvciB0aGUgbGF0aXR1ZGUgcGxvdCAobGVmdCkgaWYgd2UgaGFkIDIgbGluZXMgYW5kIG9uZSBicmVhay1wb2ludCBjYWxsZWQgYSBrbm90IGFyb3VuZCA0MCwgd2l0aCB0aGUgZmlyc3QgbGluZSBoYXZpbmcgYSBwb3NpdGl2ZSBzbG9wZSBhbmQgdGhlIHNlY29uZCB3aXRoIGEgbmVnYXRpdmUgc2xvcGUgdGhpcyB3b3VsZCBmaXQgdGhlIGRhdGEgbW9yZSBzaW1pbGFybHkgdG8gdGhlIGJsdWUgbGluZSBzaG93biBpbiB0aGUgZmlndXJlLgoKV2UgY2FuIHR1bmUgZm9yIHRoZSBudW1iZXIgb2Yga25vdHMgYnkgdXNpbmcgYSBzdGVwIGZ1bmN0aW9uIGluIHRoZSBgcmVjaXBlc2AgcGFja2FnZSBjYWxsZWQgYHN0ZXBfbnMoKWAgd2hlcmUgbnMgc3RhbmRzIGZvciBuYXR1cmFsIHNwbGluZXMuIEluIG9yZGVyIHRvIHR1bmUgZm9yIHRoZSBudW1iZXIgb2Yga25vdHMgb3IgZGVncmVlcyBvZiBmcmVlZG9tLCB3ZSBjYW4gc2V0IHRoZSBgZGVnX2ZyZWVgIGFyZ3VtZW50IHRvIGB0dW5lKClgLiBUaGlzIGlzIGhlbHBmdWwsIGJlY3Vhc2Ugd2UgYXJlbid0IGV4YWN0bHkgc3VyZSBob3cgY2xvc2VseSB3ZSBzaG91bGQgYmUgZm9sbG93aW5nIHRoZSByZWxhdGlvbnNoaXAgd2l0aCB0aGUgdmFsdWUgYW5kIG91ciBsb25naXR1ZGUgYW5kIGxhdGl0dWRlIGRhdGEgaW4gb3VyIHRyYWluaW5nIGRhdGEgdG8gYWNoaWV2ZSBnb29kIGFjY3VyYWN5IHlldCBrZWVwIG91ciBtb2RlbCBnZW5lcmFsaXphYmxlIGZvciBvdGhlciBkYXRhLiAKClRoaXMgaXMgd2hlbiBvdXIgY3Jvc3MgdmFsaWRhdGlvbiBtZXRob2RzIGJlY29tZSByZWFsbHkgaGFuZHkuIFdlIGNhbiB0ZXN0IG91dCBkaWZmZXJlbnQgdmFsdWVzIGZvciB0aGUgYGRlZ19mcmVlYCBhcmd1bWVudCBhbmQgc2VlIGhvdyBvdXIgbW9kZWwgcGVyZm9ybWFuY2UgdmFyaWVzIGFjcm9zcyBvdXIgdHJhaW5pbmcgZm9sZHMgdG8gdHJ5IHRvIGZpbmQgdGhlIG9wdGltYWwgdmFsdWUuCgpXZSB3aWxsIHVwZGF0ZSBvdXIgcmVjaXBlIHRvIGFkZCB0aGVzZSBzdGVwcy4gSXQgaXMgYSBnb29kIGlkZWEgdG8gZG8gdGhpcyBmb3IgaW5kaXZpZHVhbCBwcmVkaWN0b3JzIGJlY2F1c2UgeW91IGNhbiBuYW1lIGVhY2ggd2l0aCB0aGUgYHR1bmVgIGFyZ3VtZW50IHNvIHRoYXQgeW91IGNhbiBrZWVwIHRyYWNrIG9mIGl0IGxhdGVyLiBXZSBjYW4gc2VlIHdoYXQgd2UgaW50ZW5kIHRvIHR1bmUgd2l0aCB0aGUgYHBhcmFtZXRlcnMoKWAgZnVuY3Rpb24gb2YgdGhlIGBkaWFsc2AgcGFja2FnZS4gCgpTZWUgW2hlcmVdKHRoaXMoaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby90dW5lL2FydGljbGVzL2dldHRpbmdfc3RhcnRlZC5odG1sKSkgZm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgaW1wbGVtZW50aW5nIHRoaXMgaW4gdGlkeW1vZGVscy4KCmBgYHtyfQoKbm92ZWxfcmVjICU8PiUKICBzdGVwX25zKGxvbiwgZGVnX2ZyZWUgPSB0dW5lKCJsb24gZGYiKSkgJT4lCiAgc3RlcF9ucyhsYXQsICBkZWdfZnJlZSA9IHR1bmUoImxhdCBkZiIpKQojIG5vdmVsX3JlYyAlPD4lCiMgICBzdGVwX25zKGxhdCwgIGRlZ19mcmVlID0gdHVuZSgpKQojIG5vdmVsX3JlYwoKcG1fcGFyYW0gPC1kaWFsczo6cGFyYW1ldGVycyhub3ZlbF9yZWMpCnBtX3BhcmFtCmBgYAoKR2VuZXJhbGx5IHlvdSBjb3VsZCB1c2UgdGhlIGBncmlkXyooKWAgZnVuY3Rpb25zIG9mIHRoZSBgZGlhbHNgIHBhY2thZ2UgdG8gY3JlYXRlIHRoZSBkaWZmZXJlbnQgY29tYmluYXRpb25zIG9mIGRlZ3JlZXMgb2YgZnJlZWRvbSB0byB0ZXN0IGZvciBib3RoIHZhcmlhYmxlcyB0byBvcHRpbWl6ZSB0aGUgbW9kZWwuIEluIG91ciBjYXNlIHdlIGNhbiB2aXNpYmx5IHNlZSB0aGF0IGlmIHdlIGFkZCBtb3JlIHRoYW4gc2F5IDQgb3IgNSBkZWdyZWVzIG9mIGZyZWVkb20gd2Ugd2lsbCBsaWtlbHkgb3Zlci1maXQgdGhlIGRhdGEuIFNvIGluc3RlYWQgb2YgdXNpbmcgdGhlc2UgZnVuY3Rpb25zIHdlIHdpbGwgY3JlYXRlIG91ciBvd24gZ3JpZCB1c2luZyB0aGUgYmFzZSBgc2VxKClgIGFuZCBgZXhwYW5kLmdyaWQoKWAgZnVuY3Rpb25zLgoKYGBge3J9CiNhbiBleGFtcGxlIG9mIHdoYXQgeW91IGNvdWxkIGRvOgojc3BsaW5lX2dyaWQgPC1kaWFsczo6Z3JpZF9yZWd1bGFyKHBtX3BhcmFtLCBsZXZlbHMgPSAzKQpkZl92YWxzIDwtIHNlcSgxLCA1LCBieSA9IDIpCnNwbGluZV9ncmlkIDwtIGV4cGFuZC5ncmlkKGBsb24gZGZgID0gZGZfdmFscywgYGxhdCBkZmAgPSBkZl92YWxzKQpzcGxpbmVfZ3JpZApgYGAKCgpOb3cgd2Ugd2lsbCB0dW5lIHRoaXMgaHlwZXItcGFyYW1ldGVyIChkZWdyZWVzIG9mIGZyZWVkb20pIGZvciBib3RoIHRoZSBgbGF0YCBhbmQgYGxvbmAgdmFyaWFibGVzIHVzaW5nIG91ciBjcm9zcyB2YWxpZGF0aW9uIGZvbGRzLiBUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgdHVuZV9ncmlkKClgIGZ1bmN0aW9uIG9mIHRoZSBgdHVuZWAgcGFja2FnZS4KCmBgYHtyfQoKZGZfdHVuaW5nIDwtbG1fUE1fbW9kZWwgJT4lIAogIHR1bmU6OnR1bmVfZ3JpZChub3ZlbF9yZWMsIHJlc2FtcGxlcyA9dmZvbGRfcG0sIAogICAgICAgICAgICAgICAgICBncmlkID0gc3BsaW5lX2dyaWQpCgojZGZfdHVuaW5nIDwtUE1fd2Zsb3cgJT4lIHR1bmU6OnR1bmVfZ3JpZChyZXNhbXBsZXMgPXZmb2xkX3BtLCAKICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JpZCA9IHNwbGluZV9ncmlkLCAKICAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtX3NldCA9cG1fcGFyYW0pCgpkZl90dW5pbmcKYGBgCgoKCmBgYHtyfQoKZGZfdHVuaW5nICU+JQogIGNvbGxlY3RfbWV0cmljcygpCgpzaG93X2Jlc3QoZGZfdHVuaW5nLCBtZXRyaWMgPSAicm1zZSIsIG4gPTEpCmBgYAoKCgoKIyMjIExpbmVhciBSZWdyZXNzaW9uIE1vZGVsIHdpdGggUENBCgpXZSBjYW4gY3JlYXRlIGFub3RoZXIgd29ya2Zsb3cgdG8gc2VlIGhvdyBtb2RlbCBwZXJmb3JtYW5jZSBjb21wYXJlcyB1c2luZyBhIGRpZmZlcmVudCBtb2RlbC4gSW4gdGhpcyBjYXNlIHdlIGFyZSBnb2luZyB0byBwZXJmb3JtIHNvbWV0aGluZyBjYWxsZWQgW1ByaW5jaXBhbCBDb21wb25lbnQgQW5hbHlzaXMgb3IgUENBXShodHRwczovL21lZGl1bS5jb20vQHNhdmFzdGFtaXJrby9wY2EtYS1saW5lYXItdHJhbnNmb3JtYXRpb24tZjhhYWNkNGViMDA3KXt0YXJnZXQ9Il9ibGFuayJ9LiAKClNvIHdoYXQgaXMgUENBPwoKUENBIGlzIGEgd2lkZWx5IHVzZWQgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIG1ldGhvZCAoYSBmb3JtIG9mIHVuc3VwZXJ2aXNlZCBtYWNoaW5lIGxlYXJuaW5nKS4gSXQgY3JlYXRlcyBuZXcgdmFyaWFibGVzIHRoYXQgY2FwdHVyZSB0aGUgbW9zdCB2YXJpYXRpb24gd2l0aGluIHRoZSBkYXRhLCB5ZXQgcmVkdWNlIHRoZSBkYXRhIGRvd24gdG8ganVzdCBhIG51bWJlciBvZiBwcmluY2lwYWwgY29tcG9uZW50cy4gSXQgZG9lcyBzbyBieSB0cmFuc2Zvcm1pbmcgdGhlIGRhdGEgdXNpbmcgW29ydGhvZ29uYWxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL09ydGhvZ29uYWxpdHkjOn46dGV4dD1JbiUyMG1hdGhlbWF0aWNzJTJDJTIwb3J0aG9nb25hbGl0eSUyMGlzJTIwdGhlLHUlMkMlMjB2KSUyMCUzRCUyMDAuKXt0YXJnZXQ9Il9ibGFuayJ9IGxpbmVhciB0cmFuc2Zvcm1hdGlvbi4gSW4gb3RoZXIgd29yZHMsIGl0IGNyZWF0ZXMgbmV3IHZhcmlhYmxlcyB0aGF0IGFyZSBbbGluZWFyIGNvbWJpbmF0aW9uc10oaHR0cHM6Ly93d3cubWF0aGJvb3RjYW1wcy5jb20vbGluZWFyLWNvbWJpbmF0aW9ucy12ZWN0b3JzLyl7dGFyZ2V0PSJfYmxhbmsifSBvZiB0aGUgdmFyaWFibGVzIHdpdGhpbiB0aGUgZGF0YS4gSW1wb3J0YW50bHkgdGhlc2UgbmV3IHZhcmlhYmxlcyBhcmUgb3J0aG9nb25hbCwgbWVhbmluZyB0aGF0IHRoZSBuZXcgdmFyaWFibGVzIGhhdmUgemVybyBjb3ZhcmlhbmNlLiBJbiBzaW1wbGVyIHRlcm1zLCB3ZSBhcmUgZXhwcmVzc2luZyB1bmlxdWUgdHlwZXMgb2YgdmFyaWF0aW9uIHdpdGhpbiB0aGUgZGF0YSBhcyBuZXcgdmFyaWFibGVzLgoKQ2hlY2sgb3V0IHRoaXMgW3ZpZGVvXShodHRwczovL3lvdXR1LmJlL19VVkhuZUJVQlcwKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBtb3JlIGluZm9ybWF0aW9uLgoKYGBge3J9CmxtX1BDQV9yZWMgPC1yZWNpcGUodHJhaW5fcG0pICU+JQogICAgdXBkYXRlX3JvbGUoZXZlcnl0aGluZygpLCBuZXdfcm9sZSA9ICJwcmVkaWN0b3IiKSU+JQogICAgdXBkYXRlX3JvbGUodmFsdWUsIG5ld19yb2xlID0gIm91dGNvbWUiKSU+JQogICAgdXBkYXRlX3JvbGUoaWQsIG5ld19yb2xlID0gImlkIHZhcmlhYmxlIikgJT4lCiAgICB1cGRhdGVfcm9sZSgiZmlwcyIsIG5ld19yb2xlID0gImNvdW50eSBpZCIpICU+JQogICAgc3RlcF9kdW1teShzdGF0ZSwgY291bnR5LCBjaXR5LCB6Y3RhKSAlPiUKICAgIHN0ZXBfcGNhKGFsbF9wcmVkaWN0b3JzKCkpIApgYGAKCkxldCdzIHRha2UgYSBsb29rIHRvIHNlZSB3aGF0IHRoZSBgc3RlcF9wY2FgIGZ1bmN0aW9uIGRvZXMgdG8gb3VyIHByZWRpY3RvcnMuIFRvIGRvIHNvIHJlY2FsbCB0aGF0IHdlIG5lZWQgdG8gdXNlIHRoZSBgcHJlcGAgYW5kIGBqdWljZWAgIGZ1bmN0aW9ucyBvZiB0aGUgYHJlY2lwZXNgIHBhY2thZ2UgIG9uIG91ciByZWNpcGUuCgpgYGB7cn0KcHJlcHBlZF9yZWMgPC0gcHJlcChsbV9QQ0FfcmVjLCB2ZXJib3NlID0gVFJVRSwgcmV0YWluID0gVFJVRSApCmp1aWNlZF90cmFpbjwtIGp1aWNlKHByZXBwZWRfcmVjKQpnbGltcHNlKGp1aWNlZF90cmFpbikKYGBgCgpXZSBzdGlsbCB3YW50IHRvIHVzZSB0aGUgYGxtYCBwYWNrYWdlIGZvciBvdXIgcmVncmVzc2lvbiBzbyB3ZSBjYW4gdXNlIHRoZSBzYW1lIG1vZGVsIG9iamVjdCBhcyBiZWZvcmU6CmBgYHtyfQpsbV9QTV9tb2RlbApgYGAKCgoKYGBge3J9CnBjYV93ZmxvdyA8LXdvcmtmbG93czo6d29ya2Zsb3coKSAlPiUKICAgICAgICAgICAgd29ya2Zsb3dzOjphZGRfcmVjaXBlKGxtX1BDQV9yZWMpICU+JQogICAgICAgICAgICB3b3JrZmxvd3M6OmFkZF9tb2RlbChsbV9QTV9tb2RlbCkKCgpwY2Ffd2Zsb3cKYGBgCgoKCgoKUmVtZW1iZXIgdGhhdCB1c2luZyBgd29ya2Zsb3dzYCB3ZSBkb24ndCBhY3R1YWxseSBuZWVkIHRvIHByZXAgb3VyIHJlY2lwZSwgd2UgY2FuIGp1c3QgZml0IG91ciBtb2RlbCBkaXJlY3RseS4gCgpGaXQgdGhlIGNyb3NzIHZhbGlkYXRpb24gc2FtcGxlczoKCmBgYHtyfQpyZXNhbXBsZV9wY2FfZml0IDwtdHVuZTo6Zml0X3Jlc2FtcGxlcyhwY2Ffd2Zsb3csIHZmb2xkX3BtKQpgYGAKCgpMb29rIGF0IHRoZSBwZXJmb3JtYW5jZToKYGBge3J9CmNvbGxlY3RfbWV0cmljcyhyZXNhbXBsZV9wY2FfZml0KQpgYGAKCkFuZCB3ZSBjYW4gY29tcGFyZSB0aGlzIHdpdGggb3VyIHByZXZpb3VzIHBlcmZvcm1hbmNlOgoKYGBge3J9CmNvbGxlY3RfbWV0cmljcyhyZXNhbXBsZV9maXQpCmBgYAoKU28gd2UgY2FuIHNlZSB0aGF0IG91ciBwZXJmb3JtYW5jZSBpc24ndCBxdWl0ZSBhcyBnb29kIC0gZXNwZWNpYWxseSBpZiB3ZSBsb29rIGF0IHRoZSBgcm1zZWAgdmFsdWUuICAKCgojIyMgUmFuZG9tIEZvcmVzdAoKCk5vdyBmb3Igb25lIGxhc3QgcmVjaXBlLCB3ZSBhcmUgZ29pbmcgdG8gcHJlZGljdCB1c2luZyBhIGRlY2lzaW9uIHRyZWUgbWV0aG9kIGNhbGxlZCBbcmFuZG9tIGZvcmVzdF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmFuZG9tX2ZvcmVzdCl7dGFyZ2V0PSJfYmxhbmsifS4KCkEgW2RlY2lzaW9uIHRyZWVdKGh0dHBzOi8vbWVkaXVtLmNvbS9ncmV5YXRvbS9kZWNpc2lvbi10cmVlcy1hLXNpbXBsZS13YXktdG8tdmlzdWFsaXplLWEtZGVjaXNpb24tZGM1MDZhNDAzYWViKXt0YXJnZXQ9Il9ibGFuayJ9IGlzIGEgdG9vbCB0byBwYXJ0aXRpb24gZGF0YSBvciBhbnl0aGluZyByZWFsbHksIGJhc2VkIG9uIGEgc2VyaWVzIG9mIHNlcXVlbnRpYWwgKG9mdGVuIGJpbmFyeSkgZGVjaXNpb25zLCB3aGVyZSB0aGUgZGVjaXNpb25zIGFyZSBjaG9zZW4gIGJhc2VkIG9uIHRoZWlyIGFiaWxpdHkgdG8gb3B0aW1hbGx5IHNwbGl0IHRoZSBkYXRhLgoKSGVyZSB5b3UgY2FuIHNlZSBhIHNpbXBsZSBleGFtcGxlOgoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJodHRwczovL21pcm8ubWVkaXVtLmNvbS9tYXgvMTAwMC8xKkxNb0ptWENzUWxjaUdURXlvU04zOWcuanBlZyIpCgpgYGAKCiMjIyMgW1tzb3VyY2VdKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS91bmRlcnN0YW5kaW5nLXJhbmRvbS1mb3Jlc3QtNTgzODFlMDYwMmQyKV17dGFyZ2V0PSJfYmxhbmsifQoKSW4gdGhlIGNhc2Ugb2YgW3JhbmRvbSBmb3Jlc3RdKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9kZWNpc2lvbi10cmVlLWVuc2VtYmxlcy1iYWdnaW5nLWFuZC1ib29zdGluZy0yNjZhOGJhNjBmZDkpLCBtdWx0aXBsZSBkZWNpc2lvbiB0cmVlcyBhcmUgY3JlYXRlZCAtIGhlbmNlIHRoZSBuYW1lIGZvcmVzdCwgYW5kIGVhY2ggdHJlZSBpcyBidWlsdCB1c2luZyBhIHJhbmRvbSBzdWJzZXQgb2YgdGhlIHRyYWluaW5nIGRhdGEgKHdpdGggcmVwbGFjZW1lbnQpIC0gaGVuY2UgdGhlIGZ1bGwgbmFtZSByYW5kb20gZm9yZXN0LiBUaGlzIHJhbmRvbSBhc3BlY3QgaGVscHMgdG8ga2VlcCB0aGUgYWxnb3JpdGhtIGZyb20gb3ZlcmZpdHRpbmcgdGhlIGRhdGEuCgpUaGUgbWVhbiBvZiB0aGUgcHJlZGljdGlvbnMgZnJvbSBlYWNoIG9mIHRoZSB0cmVlcyBpcyB1c2VkIGluIHRoZSBmaW5hbCBvdXRwdXQuCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vbWlyby5tZWRpdW0uY29tL21heC8xNDAwLzAqZl9xUVBGcGRvZldHTFFxYy5wbmciKQpgYGAKCgpJbiBvdXIgY2FzZSwgdGhlIHJhbmRvbSBmb3Jlc3QgYWxnb3JpdGhtIHRoYXQgd2UgYXJlIHdvcmtpbmcgd2l0aCBkb2VzIG5vdCB3b3JrIHdlbGwgd2hlbiB0aGVyZSBhcmUgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHdpdGggbW9yZSB0aGFuIDUzIGxldmVscywgc28gd2Ugd2lsbCBuZWVkIHRvIHJlbW92ZSB0aGUgYHpjdGFgIHZhcmlhYmxlLgoKYGBge3J9CgpSRl9yZWMgPC1yZWNpcGUodHJhaW5fcG0pICU+JQogICAgdXBkYXRlX3JvbGUoZXZlcnl0aGluZygpLCBuZXdfcm9sZSA9ICJwcmVkaWN0b3IiKSU+JQogICAgdXBkYXRlX3JvbGUodmFsdWUsIG5ld19yb2xlID0gIm91dGNvbWUiKSU+JQogICAgdXBkYXRlX3JvbGUoaWQsIG5ld19yb2xlID0gImlkIHZhcmlhYmxlIikgJT4lCiAgICB1cGRhdGVfcm9sZSgiZmlwcyIsIG5ld19yb2xlID0gImNvdW50eSBpZCIpICU+JQogICAgc3RlcF9zdHJpbmcyZmFjdG9yKCJzdGF0ZSIsICJjb3VudHkiLCAiY2l0eSIpICU+JQogICAgc3RlcF9ybSgiY291bnR5IikgJT4lCiAgICBzdGVwX3JtKCJpZCIpICU+JQogICAgc3RlcF9ybSgiZmlwcyIpJT4lCiAgICBzdGVwX3JtKCJ6Y3RhIikgJT4lCiAgICBzdGVwX2NvcnIoYWxsX251bWVyaWMoKSklPiUKICAgIHN0ZXBfbnp2KGFsbF9udW1lcmljKCkpCmBgYAoKVGhlIGByYW5kX2ZvcmVzdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHBhcnNuaXBgIHBhY2thZ2UgaGFzIHRocmVlIGltcG9ydGFudCBhcmd1bWVudHMgdGhhdCBhY3QgYXMgYW4gaW50ZXJmYWNlIGZvciB0aGUgZGlmZmVyZW50IHBvc3NpYmxlIGVuZ2luZXMgdG8gcGVyZm9ybSBhIHJhbmRvbSBmb3Jlc3QgYW5hbHlzaXM6CgoxKSBtdHJ5ClRoZSBudW1iZXIgb2YgcHJlZGljdG9yIG9yIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyB0aGF0IHdpbGwgYmUgcmFuZG9tbHkgc2FtcGxlZCBhcyBvcHRpb25zIGF0IGVhY2ggc3BsaXQgd2hlbiBjcmVhdGluZyB0aGUgdHJlZSBtb2RlbHMuIFRoZSBkZWZhdWx0IG51bWJlciBmb3IgcmVncmVzc2lvbiBhbmFseXNlcyBpcyB0aGUgbnVtYmVyIG9mIHByZWRpY3RvcnMgZGl2aWRlZCBieSAzLiAKCjIpIG1pbl9uIC0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIGRhdGEgcG9pbnRzIGluIGEgbm9kZSB0aGF0IGFyZSByZXF1aXJlZCBmb3IgdGhlIG5vZGUgdG8gYmUgc3BsaXQgZnVydGhlci4KCjMpIHRyZWVzIC0gdGhlIG51bWJlciBvZiB0cmVlcyBpbiB0aGUgZW5zZW1ibGUKMTAgYW5kIDMKCmBgYHtyfQoKUE10cmVlX21vZGVsIDwtIHBhcnNuaXA6OnJhbmRfZm9yZXN0KG10cnkgPSAxMCwgbWluX24gPSAzLCBtb2RlID0gInJlZ3Jlc3Npb24iKQpQTXRyZWVfbW9kZWwKClJGX1BNX21vZGVsIDwtIAogIFBNdHJlZV9tb2RlbCAgJT4lCiAgcGFyc25pcDo6c2V0X2VuZ2luZSgicmFuZG9tRm9yZXN0IikgJT4lCiAgc2V0X21vZGUoInJlZ3Jlc3Npb24iKQoKUkZfUE1fbW9kZWwKCgpSRl93ZmxvdyA8LXdvcmtmbG93czo6d29ya2Zsb3coKSAlPiUKICAgICAgICAgICAgd29ya2Zsb3dzOjphZGRfcmVjaXBlKFJGX3JlYykgJT4lCiAgICAgICAgICAgIHdvcmtmbG93czo6YWRkX21vZGVsKFJGX1BNX21vZGVsKQpSRl93ZmxvdwpgYGAKCkZpdHRpbmcgdGhlIGRhdGEgd2l0aCBqdXN0IHBhcnNuaXAgYW5kIHdpdGggdGhlIHdvcmtmbG93OgpgYGB7cn0KCiMjanVzdCBwYXJzbmlwClJGX2ZpdCA8LSBSRl9QTV9tb2RlbCAlPiUgCnBhcnNuaXA6OmZpdCh2YWx1ZSB+LiwgZGF0YSA9anVpY2VkX3RyYWluX3JlYWR5KQoKIyMgd2l0aCB3b3JrZmxvdwpSRl93Zmxvd19maXQgPC0gcGFyc25pcDo6Zml0KFJGX3dmbG93LCBkYXRhID0gdHJhaW5fcG0pClJGX3dmbG93X2ZpdApgYGAKCgpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgdG9wIDEwIGNvbnRyaWJ1dGluZyB2YXJpYWJsZXM6CgpgYGB7cn0KUkZfd2Zsb3dfZml0JT4lIAogIHB1bGxfd29ya2Zsb3dfZml0KCkgJT4lIAogIHZpcChudW1fZmVhdHVyZXMgPSAxMCkKYGBgCgpJbnRlcmVzdGluZywgaW4gdGhlIHByZXZpb3VzIG1vZGVsIHRoZSBDTUFRIHZhbHVlcyB3ZXJlIGFsc28gaW1wb3J0YW50LCBob3dldmVyIHRoZSB2YXJpYWJsZSBhYm91dCBpZiB0aGUgbW9uaXRvciB3YXMgbG9jYXRlZCBpbiBDYWxpZm9ybmlhIG9yIG5vdCB3YXMgYWxzbyB2ZXJ5IHByZWRpY3RpdmUuIAoKTm93IGxldCdzIHRha2UgYSBsb29rIGF0IG1vZGVsIHBlcmZvcm1hbmNlIGJ5IGZpdHRpbmcgdGhlIGRhdGEgdXNpbmcgY3Jvc3MgdmFsaWRhdGlvbjoKYGBge3J9CnJlc2FtcGxlX1JGX2ZpdCA8LXR1bmU6OmZpdF9yZXNhbXBsZXMoUkZfd2Zsb3csIHZmb2xkX3BtKQpjb2xsZWN0X21ldHJpY3MocmVzYW1wbGVfUkZfZml0KQpgYGAKCk5vdyBsZXQncyBjb21wYXJlIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGlzIG1vZGVsIHdpdGggdGhlIG90aGVyczoKCmBgYHtyfQojIG91ciBpbml0aWFsIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsOgpjb2xsZWN0X21ldHJpY3MocmVzYW1wbGVfZml0KQojIG91ciBpbml0aWFsIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHdpdGggbGF0L2xvbiBkZWdyZWVzIG9mIGZyZWVkb20gdHVuaW5nOgpzaG93X2Jlc3QoZGZfdHVuaW5nLCBtZXRyaWMgPSAicm1zZSIsIG4gPTEpCiMgb3VyIFBDQSBtb2RlbDoKY29sbGVjdF9tZXRyaWNzKHJlc2FtcGxlX3BjYV9maXQpCgpgYGAKT0ssIHNvIG91ciBmaXJzdCBtb2RlbCBoYWQgYSBtZWFuIHJtc2UgdmFsdWUgb2YgMi4xOC4KVGhlIG1vZGVsIHdpdGggdGhlIGxhdC9sb25nIGRlZ3JlZXMgb2YgZnJlZWRvbSAgdHVuaW5nIGhhZCBhIG1lYW4gcm1zZSB2YWx1ZSBvZiAyLjAyLCB0aHVzIHNob3dpbmcgc29tZSBpbXByb3ZlbWVudC4KVGhlIFBDQSBtb2RlbCBoYWQgYSBtZWFuIHJtc2UgdmFsdWUgb2YgMi43Ni4KCkl0IGxvb2tzIGxpa2UgdGhlIHJhbmRvbSBmb3Jlc3QgbW9kZWwgaGFkIHRoZSBsb3dlc3Qgcm1zZSB2YWx1ZSBvZiAxLjc5LgoKCklmIHdlIHR1bmVkIG91ciByYW5kb20gZm9yZXN0IG1vZGVsIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgdHJlZXMgb3IgdGhlIHZhbHVlIGZvciBgbXRyeWAgKHdoaWNoIGlzICJUaGUgbnVtYmVyIG9mIHByZWRpY3RvcnMgdGhhdCB3aWxsIGJlIHJhbmRvbWx5IHNhbXBsZWQgYXQgZWFjaCBzcGxpdCB3aGVuIGNyZWF0aW5nIHRoZSB0cmVlIG1vZGVscyIpLCB3ZSBtaWdodCBnZXQgYSBtb2RlbCB3aXRoIGV2ZW4gYmV0dGVyIHBlcmZvcm1hbmNlLgoKCkhvd2V2ZXIsIG91ciBjcm9zcyB2YWxpZGF0ZWQgbWVhbiBybXNlIHZhbHVlIG9mIDEuNzkgaXMgcXVpdGUgZ29vZCBiZWNhdXNlIG91ciByYW5nZSBvZiB0cnVlIG91dGNvbWUgdmFsdWVzIGlzIG11Y2ggbGFyZ2VyOmByIHJhbmdlKHRlc3RfcG0kdmFsdWUpYC4KCiMjIyBGaW5hbCBNb2RlbCBQZXJmb3JtYW5jZSBFdmFsdWF0aW9uCgoKTm93IHRoYXQgd2UgaGF2ZSBkZWNpZGVkIHRoYXQgd2UgaGF2ZSByZWFzb25hYmxlIHBlcmZvcm1hbmNlIHdpdGggdGhlIHRyYWluaW5nIGRhdGEsIHdlIGNvdWxkIHN0b3AgaGVyZSBhbmQgdXNlIHRoZSBgeWFyZHN0aWNrYCBwYWNrYWdlIChhbmQgYHR1bmVgIGlmIHVzaW5nIGB3b3JrZmxvd3NgIHRvIGZpdCBvdXIgbW9kZWwpIHRvIGV2YWx1YXRlIHBlcmZvcm1hbmNlIHdpdGggb3VyIHRlc3RpbmcgZGF0YS4gCgpTbyBub3cgd2Ugd2lsbCB1c2Ugb3VyIHJhbmRvbSBmb3Jlc3QgbW9kZWwgdG8gcHJlZGljdCB2YWx1ZXMgZm9yIHRoZSBtb25pdG9ycyBpbiB0aGUgdGVzdGluZyBkYXRhLgoKVXNpbmcgYHBhcnNuaXBgIHdlIHdvdWxkIG5lZWQgdG8gdXNlIHRoZSBiYWtlZCBkYXRhIHRlc3RpbmcgZGF0YS4gV2l0aCB0aGUgYHdvcmtmbG93c2AgcGFja2FnZSwgd2UgY291bGQgdXNlIHRoZSByYXcgdGVzdGluZyBkYXRhLgoKSW1wb3J0YW50bHksIElEIHZhcmlhYmxlcyBhcmUgbm90IGRlYWx0IHdpdGggYXMgbmljZWx5IGFzIHdpdGggdGhlIGB3b3JrZmxvd3NgIHBhY2thZ2Ugc28gd2Ugd291bGQgbmVlZCB0byByZW1vdmUgdGhlbS4gV2UgZGlkIHRoaXMgYWJvdmUgd2hlbiBjcmVhdGVkIHRoZSBwcm9jZXNzZWQgdHJhaW5pbmcgZGF0YSBmb3IgdGhpcyBtb2RlbCwgdGhlIGBqdWljZWRfdHJhaW5gIGRhdGEgYXMgd2VsbC4KCmBgYHtyfQoKIGJha2VkX3Rlc3RfcG1fcmVhZHkgPC1iYWtlZF90ZXN0X3BtICU+JXNlbGVjdCggLSJpZCIsIC0iZmlwcyIpCiB2YWx1ZXNfcHJlZF9wYXJzbmlwIDwtcHJlZGljdChSRl9maXQsIGJha2VkX3Rlc3RfcG1fcmVhZHkpCiB2YWx1ZXNfcHJlZF9wYXJzbmlwCiAKIyB1c2luZyB0aGUgd29ya2Zsb3dzIHZlcnNpb24KdmFsdWVzX3ByZWRfd2ZzIDwtIAogIHByZWRpY3QoUkZfd2Zsb3dfZml0LCB0ZXN0X3BtKSAlPiUgCiAgYmluZF9jb2xzKHRlc3RfcG0gJT4lIHNlbGVjdCh2YWx1ZSwgZmlwcywgY291bnR5LCBpZCkpIAp2YWx1ZXNfcHJlZF93ZnMKCiNtb2RlbCBwZXJmb3JtYW5jZSB3aXRoIHRlc3Qgc2V0CnlhcmRzdGljazo6bWV0cmljcyh2YWx1ZXNfcHJlZF93ZnMsIHRydXRoID0gdmFsdWUsIGVzdGltYXRlID0gLnByZWQpCgpgYGAKQXdlc29tZSEgV2UgY2FuIHNlZSB0aGF0IG91ciBybXNlIG9mIDEuNDkgaXMgcXVpdGUgc2ltaWxhciB3aXRoIG91ciB0ZXN0aW5nIGRhdGEuIFdlIGFjaGlldmVkIHF1aXRlIGdvb2QgcGVyZm9ybWFuY2UsIHdoaWNoIHN1Z2dlc3RzIHRoYXQgd2Ugd291bGQgY291bGQgcHJlZGljdCBvdGhlciBsb2NhdGlvbnMgd2l0aCBtb3JlIHNwYXJzZSBtb25pdG9yaW5nIGJhc2VkIG9uIG91ciBwcmVkaWN0b3JzIHdpdGggcmVhc29uYWJsZSBhY2N1cmFjeS4KCldlIGNvdWxkIGFsc28gdXNlIHRoZSBgbGFzdF9maXQoKWAgZnVuY3Rpb24gb2YgdGhlIGB0dW5lYCBwYWNrYWdlIHRvIGxvb2sgYXQgcGVyZm9ybWFuY2UgaWYgd2UgY2hvc2UgdG8gY3JlYXRlIGEgd29ya2Zsb3cgdXNpbmcgdGhlIGB3b3JrZmxvd3NgIHBhY2thZ2UuCgpgYGB7cn0Kb3ZlcmFsbGZpdCA8LXR1bmU6Omxhc3RfZml0KFJGX3dmbG93LCBwbV9zcGxpdCkKICMgb3IKb3ZlcmFsbGZpdCA8LVJGX3dmbG93ICU+JQogIHR1bmU6Omxhc3RfZml0KHBtX3NwbGl0KQoKb3ZlcmFsbGZpdCQubWV0cmljc1tbMV1dCmBgYAoKV2UgY291bGQgY2hlY2sgb3V0IHRlc3QgcGVyZm9ybWFuY2UgdXNpbmcgdGhlIGBjb2xsZWN0X21ldHJpY3MoKWAgZnVuY3Rpb24gb2YgdGhlIGB0dW5lYCBwYWNrYWdlLgoKCmBgYHtyfQp0ZXN0X3BlcmZvcm1hbmNlIDwtIG92ZXJhbGxmaXQgICU+JXR1bmU6OmNvbGxlY3RfbWV0cmljcygpCnRlc3RfcGVyZm9ybWFuY2UKYGBgCgpIZXJlIHlvdSBjYW4gc2VlIHRoZSBwcmVkaWN0aW9ucyBmb3IgdGhlIHRlc3Qgc2V0ICh0aGUgMjkyIHJvd3Mgd2l0aCBwcmVkaWN0aW9ucyBvdXQgb2YgdGhlIDg3NiBvcmlnaW5hbCBtb25pdG9yIHZhbHVlcykgYWxzbyB1c2luZyB0aGUgYHR1bmVgIHBhY2thZ2Ugd2l0aCB0aGUgYGNvbGxlY3RfcHJlZGljdGlvbnMoKWAgZnVuY3Rpb24uCgojIyMjIHsuc2Nyb2xsYWJsZSB9CmBgYHtyfQp0ZXN0X3ByZWRpY3Rpb25zIDwtIG92ZXJhbGxmaXQgICU+JXR1bmU6OmNvbGxlY3RfcHJlZGljdGlvbnMoKQp0ZXN0X3ByZWRpY3Rpb25zICU+JQogIHByaW50KG4gPSAxZTMpCmBgYAoKIyMjIwoKIyMgRGF0YSBWaXN1YWxpemF0aW9uCgpPdXIgbWFpbiBxdWVzdGlvbiBmb3IgdGhpcyBjYXNlIHN0dWR5IHdhczogIAoKMSkgQ2FuIHdlIHByZWRpY3QgYW5udWFsIGF2ZXJhZ2UgYWlyIHBvbGx1dGlvbiBjb25jZW50cmF0aW9ucyBhdCB0aGUgZ3JhbnVsYXJpdHkgb2YgemlwIGNvZGUgcmVnaW9uYWwgbGV2ZWxzIHVzaW5nIHByZWRpY3RvcnMgc3VjaCBhcyBkYXRhIGFib3V0IHBvcHVsYXRpb24gZGVuc2l0eSwgdXJiYW5pemF0aW9uLCByb2FkIGRlbnNpdHksIGFzIHdlbGwgYXMsIHNhdGVsbGl0ZSBwb2xsdXRpb24gZGF0YSBhbmQgY2hlbWljYWwgbW9kZWxpbmcgZGF0YT8KCldlIGhhdmUgaW5kZWVkIGNyZWF0ZWQgYSBtb2RlbCB0aGF0IGNhbiBwcmVkaWN0IGZpbmUgcGFydGljdWxhdGUgbWF0dGVyIGFpciBwb2xsdXRpb24gbGV2ZWxzIGJhc2VkIG9uIG91ciBwcmVkaWN0b3IgdmFyaWFibGVzLgoKTm93IGxldCdzIG1ha2UgYSBwbG90IG9mIG91ciBwcmVkaWN0ZWQgdmFsdWVzIGFuZCB0aGUgdHJ1ZSB2YWx1ZXMuCgpGaXJzdCwgbGV0J3Mgc3RhcnQgYnkgbWFraW5nIGEgcGxvdCBvZiBvdXIgbW9uaXRvcnM6CgpXZSB3aWxsIHVzZSB0aGUgZm9sbG93aW5nIHBhY2thZ2VzIHRvIGNyZWF0ZSBhIG1hcCBvZiB0aGUgVVM6CjEpYHNmYAoyKWBtYXBzYAoyKWBybmF0dXJhbGVhcnRoYAozKWByZ2Vvc2AKCkFjY29yZGluZyB0byB0aGlzIFtsaW5rIG9uIHdpa2lwZWRpYV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9leHRyZW1lX3BvaW50c19vZl90aGVfVW5pdGVkX1N0YXRlcyNXZXN0ZXJubW9zdCksIHRoZXNlIGFyZSB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSBib3VuZHMgb2YgdGhlIGNvbnRpbmVudGFsIFVTLgoKdG9wID0gNDkuMzQ1Nzg2OCAjIG5vcnRoIGxhdApsZWZ0ID0gLTEyNC43ODQ0MDc5ICMgd2VzdCBsb25nCnJpZ2h0ID0gLTY2Ljk1MTM4MTIgIyBlYXN0IGxvbmcKYm90dG9tID0gIDI0Ljc0MzMxOTUgIyBzb3V0aCBsYXQKCldlIHdpbGwgc3RhcnQgd2l0aCBnZXR0aW5nIGFuIG91dGxpbmUgb2YgdGhlIFVTIHdpdGggdGhlIGBuZV9jb3VudHJpZXMoKWAgZnVuY3Rpb24gb2YgdGhlIGBybmF0dXJhbGVhcnRoYCBwYWNrYWdlLgpgYGB7cn0KbGlicmFyeSgicmdlb3MiKQoKd29ybGQgPC0gcm5hdHVyYWxlYXJ0aDo6bmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikKCmdncGxvdChkYXRhID0gd29ybGQpICsKICAgIGdlb21fc2YoKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSBwbSwgYWVzKHggPSBsb24sIHkgPSBsYXQpLCBzaXplID0gMiwgCiAgICAgICAgc2hhcGUgPSAyMywgZmlsbCA9ICJkYXJrcmVkIikgKwogICAgY29vcmRfc2YoeGxpbSA9IGMoLTEyNSwgLTY2KSwgeWxpbSA9IGMoMjQuNSwgNTApLCBleHBhbmQgPSBGQUxTRSkKYGBgCgpOb3cgbGV0J3MgYWRkIGNvdW50eSBsaW5lcy4KCkNvdW50eSBncmFwaGljYWwgZGF0YSBpcyBhdmFpbGFibGUgZnJvbSB0aGUgYG1hcHNgIHBhY2thZ2UuIFRoZSBgc2ZgIHBhY2thZ2Ugd2hpY2ggaXMgc2hvcnQgZm9yIHNpbXBsZSBmZWF0dXJlcyBjcmVhdGVzIGEgZGF0YSBmcmFtZSBhYm91dCB0aGlzIGdyYXBoaWNhbCBkYXRhIHNvIHRoYXQgd2UgY2FuIHdvcmsgd2l0aCBpdC4KCmBgYHtyfQoKY291bnRpZXMgPC0gc2Y6OnN0X2FzX3NmKG1hcHM6Om1hcCgiY291bnR5IiwgcGxvdCA9IEZBTFNFLCBmaWxsID0gVFJVRSkpCgptb25pdG9ycyA8LWdncGxvdChkYXRhID0gd29ybGQpICsKICAgIGdlb21fc2YoZGF0YSA9IGNvdW50aWVzLCBmaWxsID0gTkEsIGNvbG9yID0gZ3JheSguNSkpKwogICAgZ2VvbV9wb2ludChkYXRhID0gcG0sIGFlcyh4ID0gbG9uLCB5ID0gbGF0KSwgc2l6ZSA9IDIsIAogICAgICAgIHNoYXBlID0gMjMsIGZpbGwgPSAiZGFya3JlZCIpICsKICAgIGNvb3JkX3NmKHhsaW0gPSBjKC0xMjUsIC02NiksIHlsaW0gPSBjKDI0LjUsIDUwKSwgZXhwYW5kID0gRkFMU0UpKwogICAgZ2d0aXRsZSgiTW9uaXRvciBMb2NhdGlvbnMiKSsKICAgIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSkKCm1vbml0b3JzCmBgYAoKTm93IGxldCdzIGFkZCBhIGZpbGwgYXQgdGhlIGNvdW50eSBsZXZlbCBmb3IgdGhlIHRydWUgbW9uaXRvciB2YWx1ZXMgb2YgYWlyIHBvbGx1dGlvbjoKCmBgYHtyfQoKaGVhZChjb3VudGllcykKCnBtIDwtcmVhZHI6OnJlYWRfY3N2KGhlcmUoImRvY3MiLCAicG0yNV9kYXRhLmNzdiIpKQpjb3VudGllcyAlPD4lIHRpZHlyOjpzZXBhcmF0ZShJRCwgaW50byA9IGMoInN0YXRlIiwgImNvdW50eSIpLCBzZXAgPSAiLCIpCgpjb3VudGllc1tbImNvdW50eSJdXSA8LXN0cmluZ3I6OnN0cl90b190aXRsZShjb3VudGllc1tbImNvdW50eSJdXSkKCm1hcF9kYXRhIDwtaW5uZXJfam9pbihjb3VudGllcywgcG0sIGJ5ID0gImNvdW50eSIpCgp0cnV0aDwtZ2dwbG90KGRhdGEgPSB3b3JsZCkgKwogICAgZ2VvbV9zZigpICsKICAgIGdlb21fc2YoZGF0YSA9IG1hcF9kYXRhLCBhZXMoZmlsbCA9IHZhbHVlKSkgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzX2ModHJhbnMgPSAic3FydCIsIGFscGhhID0gLjQpICsKICAgICAgI2dlb21fcG9pbnQoZGF0YSA9IHBtLCBhZXMoeCA9IGxvbiwgeSA9IGxhdCksIHNpemUgPSAxLjUsIGFscGhhID0gMiwKICAgICAgICMgc2hhcGUgPSAyMywgZmlsbCA9ICJkYXJrcmVkIikgKwogICAgICAgIGNvb3JkX3NmKHhsaW0gPSBjKC0xMjUsIC02NiksIHlsaW0gPSBjKDI0LjUsIDUwKSwgZXhwYW5kID0gRkFMU0UpKwogICAgICBnZ3RpdGxlKCJNb25pdG9yIFBNfjIuNX4gbGV2ZWxzIikKdHJ1dGgKCgoKdHJ1dGggPC1nZ3Bsb3QoZGF0YSA9IHdvcmxkKSArCiAgICBnZW9tX3NmKCkgKwogICAgZ2VvbV9zZihkYXRhID0gbWFwX2RhdGEsIGFlcyhmaWxsID0gdmFsdWUpKSArCiAgICAjc2NhbGVfZmlsbF92aXJpZGlzX2ModHJhbnMgPSAic3FydCIsIGFscGhhID0gLjQpICsKICAgICAgI2dlb21fcG9pbnQoZGF0YSA9IHBtLCBhZXMoeCA9IGxvbiwgeSA9IGxhdCksIHNpemUgPSAxLjUsIGFscGhhID0yLAogICAgICAjICBzaGFwZSA9IDIzLCBmaWxsID0gImRhcmtyZWQiKSArCiAgICAgICAgY29vcmRfc2YoeGxpbSA9IGMoLTEyNSwgLTY2KSwgeWxpbSA9IGMoMjQuNSwgNTApLCBleHBhbmQgPSBGQUxTRSkrCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3Vycz10b3BvLmNvbG9ycyg3KSxuYS52YWx1ZSA9ICJ0cmFuc3BhcmVudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKDAsMTAsMjApLGxhYmVscz1jKDAsMTAsMjApLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHM9YygwLDIzLjUpLCBuYW1lID0gIlBNIHVnL20zIikrCiAgZ2d0aXRsZSgiVHJ1ZSBQTSJ+Mi41fiIgbGV2ZWxzIikrCiAgICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpCgp0cnV0aAoKYGBgCgoKTm93IGxldCdzIGRvIHRoZSBzYW1lIHdpdGggb3VyIHByZWRpY3RlZCB2YWx1ZXMuCgpMZXQncyBncmFiIGJvdGggdGhlIHRlc3RpbmcgYW5kIHRyYWluaW5nIGZpdHRlZCB2YWx1ZXMgc28gdGhhdCB3ZSBoYXZlIGFzIG11Y2ggZGF0YSBhcyBwb3NzaWJsZS4gCkluIHRoaXMgY2FzZSwgdGhlIG91dHB1dCBzdHJ1Y3R1cmUgZm9yIHRoZSB0cmFpbmluZyBkYXRhIGZpdCBpcyBzbGlnaHRseSBkaWZmZXJlbnQgdXNpbmcgYHJhbmRvbUZvcmVzdGAuIFRoZSBmaXR0ZWQgdmFsdWVzIGFyZSBjYWxsZWQgYHByZWRpY3RlZGAgYW5kIHRoZSBgYnJvb21gIGZ1bmN0aW9ucyBsaWtlIGB0aWR5KClgIGFuZCBgYXVnbWVudCgpYCB3aWxsIG5vdCB3b3JrLiBTbyB3ZSB3aWxsIG1hbnVhbGx5IGdyYWIgdGhlIGZpdHRlZCB0cmFpbmluZyBkYXRhIHZhbHVlcy4KCmBgYHtyfQoKI3Rlc3QgZGF0YQp2YWx1ZXNfcHJlZF93ZnMKCiN0cmFpbmluZyBkYXRhCnRyYWluaW5nX1JGX2VzdGltYXRlcyA8LVJGX2ZpdFtbImZpdCJdXVtbInByZWRpY3RlZCJdXQp0cmFpbmluZ19SRl9lc3RpbWF0ZXMgPC10aWJibGUoIi5wcmVkIiA9dHJhaW5pbmdfUkZfZXN0aW1hdGVzLAp2YWx1ZT0gdHJhaW5fcG0kdmFsdWUsIGZpcHMgPSB0cmFpbl9wbSRmaXBzLCAgY291bnR5ID0gdHJhaW5fcG0kY291bnR5LCBpZCA9dHJhaW5fcG0kaWQpCgphbGxfcHJlZCA8LWJpbmRfcm93cyh2YWx1ZXNfcHJlZF93ZnMsIHRyYWluaW5nX1JGX2VzdGltYXRlcyApCgoKYGBgCgoKYGBge3J9Cm1hcF9kYXRhIDwtaW5uZXJfam9pbihjb3VudGllcywgYWxsX3ByZWQsIGJ5ID0gImNvdW50eSIpCgpwcmVkIDwtZ2dwbG90KGRhdGEgPSB3b3JsZCkgKwogICAgZ2VvbV9zZigpICsKICAgIGdlb21fc2YoZGF0YSA9IG1hcF9kYXRhLCBhZXMoZmlsbCA9IC5wcmVkKSkgKwogICAgI3NjYWxlX2ZpbGxfdmlyaWRpc19jKHRyYW5zID0gInNxcnQiLCBhbHBoYSA9IC40KSArCiAgICAgICNnZW9tX3BvaW50KGRhdGEgPSBwbSwgYWVzKHggPSBsb24sIHkgPSBsYXQpLCBzaXplID0gMS41LCBhbHBoYSA9MiwKICAgICAgIyAgc2hhcGUgPSAyMywgZmlsbCA9ICJkYXJrcmVkIikgKwogICAgICAgIGNvb3JkX3NmKHhsaW0gPSBjKC0xMjUsIC02NiksIHlsaW0gPSBjKDI0LjUsIDUwKSwgZXhwYW5kID0gRkFMU0UpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG91cnM9dG9wby5jb2xvcnMoNyksbmEudmFsdWUgPSAidHJhbnNwYXJlbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3M9YygwLDEwLDIwKSxsYWJlbHM9YygwLDEwLDIwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoMCwyMy41KSwgbmFtZSA9ICJQTSB1Zy9tMyIpKwogIGdndGl0bGUoIlByZWRpY3RlZCBQTSJ+Mi41fiIgbGV2ZWxzIikrCiAgICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpCgpwcmVkCgpgYGAKCgoKYGBge3J9CmNvd3Bsb3Q6OnBsb3RfZ3JpZChtb25pdG9ycywgdHJ1dGgsIHByZWQpCmBgYAoKCmBgYHtyfQpjb3dwbG90OjpwbG90X2dyaWQodHJ1dGgsIHByZWQsbnJvdyA9IDIgKQoKYGBgCgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KCnBuZyhoZXJlOjpoZXJlKCJpbWciLCAibWFpbl9wbG90X21hcHMucG5nIiksIGhlaWdodCA9IDE1MDAsIHdpZHRoID0gMjAwMCwgcmVzID0gMzAwKQpjb3dwbG90OjpwbG90X2dyaWQodHJ1dGgsIHByZWQsbnJvdyA9IDIgKQoKZGV2Lm9mZigpCgpgYGAKCiMjIFN1bW1hcnkKCkxldCdzIHJldmlldyBldmVyeXRoaW5nOgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iODAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCJlY29zeXN0ZW0ucG5nIikpCmBgYAoKCldlIGhhdmUgZXhwbG9yZWQgZ3JhdmltZXRyaWMgbW9uaXRvcmluZyBkYXRhIG9mIGZpbmUgcGFydGljdWxhdGUgbWF0dGVyIGFpciBwb2xsdXRpb24uIFdlIGhhdmUgdXRpbGl6ZWQgdGhlIHRpZHltb2RlbHMgZWNvc3lzdGVtIG9mIHBhY2thZ2VzIHRvIHByZWRpY3QgbW9uaXRvciB2YWx1ZXMgdXNpbmcgYSB2YXJpZXR5IG9mIHByZWRpY3RvcnMsIGFsc28ga25vd24gYXMgZXhwbGFuYXRvcnkgdmFyaWFibGVzLCBpbmNsdWRpbmcgc2F0ZWxsaXRlIGRhdGEsIHJvYWQgZGVuc2l0eSBkYXRhLCBhbmQgcG9wdWxhdGlvbiBkZW5zaXR5LCBhbW9uZyBvdGhlcnMuIE91ciBtb2RlbCBjb3VsZCBub3cgYmUgZXh0ZW5kZWQgdG8gYmUgdXNlZCB0byBwcmVkaWN0IHBvbGx1dGlvbiBsZXZlbHMgaW4gYXJlYXMgcG9vciAgbW9uaXRvcmluZywgdG8gaGVscCBpZGVudGlmeSByZWdpb25zIHdoZXJlIHBvcHVsYXRpb25zIG1heWJlIGVzcGVjaWFsbHkgYXQgcmlzayBmb3IgdGhlIGhlYWx0aCBlZmZlY3RzIG9mIGFpciBwb2xsdXRpb24uICAKCldlIGxlYXJuZWQgdGhhdCB0aGVyZSBhcmUgdHdvIG1ham9yIHR5cGVzIG9mIHdoYXQgaXMgY2FsbGVkIHN1cGVydmlzZWQgbWFjaGluZSBsZWFybmluZzogcHJlZGljdGlvbiBhbmQgY2xhc3NpZmljYXRpb24uIFdlIGxlYXJuZWQgdGhhdCBwcmVkaWN0aW9uIGlzIHVzZWQgd2hlbiB0aGUgb3V0Y29tZSB2YXJpYWJsZSBpcyBudW1lcmljIGFuZCBjbGFzc2lmaWNhdGlvbiBpcyBwZXJmb3JtZWQgd2hlbiB0aGUgb3V0Y29tZSB2YXJpYWJsZSBpcyBjYXRlZ29yaWNhbC4gIAoKV2UgcGVyZm9ybWVkIHRoZSBtYWpvciBzdGVwcyBvZiBtYWNoaW5lIGxlYXJuaW5nIHRoYXQgd2UgaW50cm9kdWNlZCBpbiB0aGUgYmVnaW5uaW5nIG9mIHRoZSBkYXRhIGFuYWx5c2lzOiAgCgoxKSBEYXRhIGV4cGxvcmF0aW9uICAKCldlIHVzZWQgYSBwYWNrYWdlcyBsaWtlIGBza2ltcmAsIGBzdW1tYXJ5dG9vbHNgLCBgY29ycnBsb3RgLCBgZ2djb3JycGxvdGAsIGFuZCBgR0dhbGx5YCB0byBiZXR0ZXIgdW5kZXJzdGFuZCBvdXIgZGF0YS4gVGhlc2UgcGFja2FnZXMgZ2F2ZSBjYW4gdGVsbCB1cyBob3cgbWFueSBtaXNzaW5nIHZhbHVlcyBlYWNoIHZhcmlhYmxlIGhhcyAoaWYgYW55KSwgdGhlIGNsYXNzIG9mIGVhY2ggdmFyaWFibGUsIHRoZSBkaXN0cmlidXRpb24gb2YgdmFsdWVzIGZvciBlYWNoIHZhcmlhYmxlLCB0aGUgc3BhcnNpdHkgb2YgZWFjaCB2YXJpYWJsZSwgYW5kIHRoZSBsZXZlbCBvZiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHZhcmlhYmxlcy4gIAoKMikgRGF0YSBzcGxpdHRpbmcgCgpXZSB1c2VkIHRoZSBgcnNhbXBsZWAgcGFja2FnZSB0byBmaXJzdCBwZXJmb3JtIGFuIGluaXRpYWwgc3BsaXQgb2Ygb3VyIGRhdGEgaW50byB0d28gcGllY2VzOiBhIHRyYWluaW5nIHNldCBhbmQgYSB0ZXN0aW5nIHNldC4gVGhlIHRyYWluaW5nIHNldCB3YXMgdXNlZCB0byBvcHRpbWl6ZSB0aGUgbW9kZWwsIHdoaWxlIHRoZSB0ZXN0aW5nIHNldCB3YXMgdXNlZCBvbmx5IHRvIGV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBvdXIgZmluYWwgbW9kZWwuIFdlIGFsc28gdXNlZCB0aGUgYHJzYW1wbGVgIHBhY2thZ2UgdG8gY3JlYXRlIGNyb3NzIHZhbGlkYXRpb24gc3Vic2V0cyBvZiBvdXIgdHJhaW5pbmcgZGF0YS4gVGhpcyBhbGxvd2VkIHVzIHRvIGJldHRlciBhc3Nlc3MgdGhlIHBlcmZvcm1hbmNlIG9mIG91ciB0ZXN0ZWQgbW9kZWxzIHVzaW5nIG91ciB0cmFpbmluZyBkYXRhLiAgCgozKSBWYXJpYWJsZSBhc3NpZ25tZW50IGFuZCBwcmVwcm9jZXNzaW5nICAgCgpXZSB1c2VkIHRoZSBgcmVjaXBlc2AgcGFja2FnZSB0byBhc3NpZ24gdmFyaWFibGUgcm9sZXMgKHN1Y2ggYXMgb3V0Y29tZSwgcHJlZGljdG9yLCBhbmQgaWQgdmFyaWFibGUpLiBXZSBhbHNvIHVzZWQgdGhpcyBwYWNrYWdlIHRvIGNyZWF0ZSBhIHJlY2lwZSBmb3IgcHJlcHJvY2Vzc2luZyBvdXIgdHJhaW5pbmcgYW5kIHRlc3RpbmcgZGF0YS4gVGhpcyBpbnZvbHZlZCBzdGVwcyBzdWNoIGFzOiBgIHN0ZXBfZHVtbXlgIHRvIGNyZWF0ZSBkdW1teSBudW1lcmljIGVuY29kaW5ncyBvZiBvdXIgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCBgc3RlcF9jb3JyYCB0byByZW1vdmUgaGlnaGx5IGNvcnJlbGF0ZWQgdmFyaWFibGVzLCBgc3RlcF9uenZgIHRvIHJlbW92ZSBuZWFyIHplcm8gdmFyaWFuY2UgdmFyaWFibGVzIHRoYXQgd291bGQgY29udHJpYnV0ZSBsaXR0bGUgdG8gb3VyIG1vZGVsIGFuZCBwb3RlbnRpYWxseSBhZGQgbm9pc2UuICBXZSBsZWFybmVkIHRoYXQgb25jZSBvdXIgcmVjaXBlIHdhcyBjcmVhdGVkIGFuZCBwcmVwcGVkIHVzaW5nIGBwcmVwKClgd2UgY291bGQgZXh0cmFjdCB0aGUgcHJlLXByb2Nlc3NlZCB0cmFpbmluZyBkYXRhIHVzaW5nIGBqdWljZSgpYCBvciBvdXIgcHJlLXByb2Nlc3NlZCB0ZXN0aW5nIGRhdGEgdXNpbmcgYGJha2UoKWAuIFdlIGFsc28gbGVhcm5lZCB0aGF0IGlmIHdlIHVzZWQgdGhlIG5ld2VyIHdvcmtmbG93cyBwYWNrYWdlIHRoYXQgd2UgZGlkIG5vdCBuZWVkIHRvIHRoZSBgcHJlcCgpYCwgYGp1aWNlKClgLCBvciBgYmFrZSgpYCBmdW5jdGlvbnMsIGJ1dCB0aGF0IGl0IGlzIHN0aWxsIHVzZWZ1bCB0byBrbm93IGhvdyB0byBkbyBzbyBpZiB3ZSB3YW50IHRvIGxvb2sgYXQgb3VyIGRhdGEgYW5kIGhvdyB0aGUgcmVjaXBlIGlzIGluZmx1ZW5jaW5nIGl0IG1vcmUgZGVlcGx5LiAgCgo0KSBNb2RlbCBzcGVjaWZpY2F0aW9uLCBmaXR0aW5nLCB0dW5pbmcgYW5kIHBlcmZvcm1hbmNlIGV2YWx1YXRpb24gdXNpbmcgdGhlIHRyYWluaW5nIGRhdGEgIAoKV2UgbGVhcm5lZCB0aGF0IHRoZSBtb2RlbCBuZWVkcyB0byBmaXJzdCBiZSBmaXQgdG8gdGhlIHRyYWluaW5nIGRhdGEuIFdlIGxlYXJuZWQgdGhhdCBpbiBib3RoIGNsYXNzaWZpY2F0aW9uIGFuZCBwcmVkaWN0aW9uLCB0aGUgbW9kZWwgaXMgZml0IHRvIHRoZSB0cmFpbmluZyBkYXRhIGFuZCB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGFyZSB1c2VkIHRvIGVzdGltYXRlIG51bWVyaWMgdmFsdWVzIChpbiB0aGUgY2FzZSBvZiBwcmVkaWN0aW9uKSBvciBjYXRlZ29yaWNhbCB2YWx1ZXMgKGluIHRoZSBjYXNlIG9mIGNsYXNzaWZpY2F0aW9uKSBvZiB0aGUgb3V0Y29tZSB2YXJpYWJsZSBvZiBpbnRlcmVzdC4gV2UgbGVhcm5lZCB0aGF0IHdlIHNwZWNpZnkgdGhlIG1vZGVsIGFuZCBpdHMgc3BlY2lmaWNhdGlvbnMgdXNpbmcgdGhlIGBwYXJuc2lwYCBwYWNrYWdlIGFuZCB0aGF0IHdlIGFsc28gdXNlIHRoaXMgcGFja2FnZSB0byBmaXQgdGhlIG1vZGVsIHVzaW5nIHRoZSBgZml0KClgIGZ1bmN0aW9uLiBXZSBsZWFybmVkIHRoYXQgd2UgaWYganVzdCB1c2UgYHBhcnNuaXBgIHRvIGZpdCB0aGUgbW9kZWwsIHRoZW4gd2UgbmVlZCB0byB1c2UgdGhlIHByZS1wcm9jZXNzZWQgdHJhaW5pbmcgZGF0YSAob3V0cHV0IGZyb20gYGp1aWNlKClgKS4gV2UgbGVhcm5lZCB0aGF0IHdlIGNhbiB1c2UgdGhlIHJhdyB0cmFpbmluZyBkYXRhIGlmIHdlIHVzZSB0aGUgYHdvcmtmbG93c2AgcGFja2FnZSB0byBjcmVhdGUgYSB3b3JrZmxvdyB0aGF0IHByZS1wcm9jZXNzZXMgb3VyIGRhdGEgZm9yIHVzLiAgIAoKV2UgbGVhcm5lZCB0aGF0IGlmIHRoZSBtb2RlbCBmaXRzIHdlbGwgdGhhbiB0aGUgZXN0aW1hdGVkIHZhbHVlcyB3aWxsIGJlIHZlcnkgc2ltaWxhciB0byB0aGUgdHJ1ZSBvdXRjb21lIHZhcmlhYmxlIHZhbHVlcyBpbiBvdXIgdHJhaW5pbmcgZGF0YS4gV2UgbGVhcm5lZCB0aGF0IHdlIGNhbiBhc3Nlc3MgbW9kZWwgcGVyZm9ybWFuY2UgdXNpbmcgdGhlIGB5YXJkc3RpY2tgIHBhY2thZ2UgYW5kIHRoZSBgbWV0cmljcygpYCBmdW5jdGlvbi4gV2UgYWxzbyBsZWFybmVkIHRoYXQgd2UgY2FuIHVzZSBzdWJzZXRzIG9mIG91ciB0cmFpbmluZyBkYXRhICh3aGljaCB3ZSBjcmVhdGVkIHdpdGggdGhlIGByc2FtcGxlYCBwYWNrYWdlKSB0byBwZXJmb3JtIGNyb3NzIHZhbGlkYXRpb24gdG8gZ2V0IGEgYmV0dGVyIGVzdGltYXRlIGFib3V0IHRoZSBwZXJmb3JtYW5jZSBvZiBvdXIgbW9kZWwgdXNpbmcgb3VyIHRyYWluaW5nIGRhdGEsIGFzIHdlIHdhbnQgb3VyIHJlc3VsdHMgdG8gYmUgZ2VuZXJhbGl6YWJsZSBhbmQgdG8gcGVyZm9ybSB3ZWxsIHdpdGggb3RoZXIgZGF0YSwgbm90IGp1c3Qgb3VyIHRyYWluaW5nIGRhdGEuIFdlIHVzZWQgdGhlIGBmaXRfcmVzYW1wbGVzKClgIGZ1bmN0aW9uIG9mIHRoZSB0dW5lIHBhY2thZ2UgdG8gZml0IG91ciBtb2RlbCBvbiBvdXIgZGlmZmVyZW50IHRyYWluaW5nIGRhdGEgc3Vic2V0cyBhbmQgdGhlIGBjb2xsZWN0X21ldHJpY3MoKWAgZnVuY3Rpb24gKGFsc28gb2YgdGhlIGB0dW5lYCBwYWNrYWdlKSB0byBldmFsdWF0ZSBtb2RlbCBwZXJmb3JtYW5jZSB1c2luZyB0aGVzZSBzdWJzZXRzLiAgV2UgYWxzbyBsZWFybmVkIHRoYXQgd2UgY2FuIHBvdGVudGlhbGx5IGltcHJvdmUgbW9kZWwgcGVyZm9ybWFuY2UgYnkgdHVuaW5nIGFzcGVjdHMgYWJvdXQgdGhlIG1vZGVsIGNhbGxlZCBbaHlwZXItcGFyYW1ldGVyc10oaHR0cHM6Ly93d3cuZGF0YWNhbXAuY29tL2NvbW11bml0eS90dXRvcmlhbHMvcGFyYW1ldGVyLW9wdGltaXphdGlvbi1tYWNoaW5lLWxlYXJuaW5nLW1vZGVscyl7dGFyZ2V0PSJfYmxhbmsifSB0byBkZXRlcm1pbmUgdGhlIGJlc3Qgb3B0aW9uIGZvciBtb2RlbCBwZXJmb3JtYW5jZS4gV2UgbGVhcm5lZCB0aGF0IHdlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBgdHVuZWAgYW5kIGBkaWFsc2AgcGFja2FnZXMgYW5kIGV2YWx1YXRpbmcgdGhlIHBlcmZvcm1hbmNlIG9mIG91ciBtb2RlbCB3aXRoIHRoZSBkaWZmZXJlbnQgaHlwZXItcGFyYW1ldGVyIG9wdGlvbnMgYW5kIG91ciB0cmFpbmluZyBkYXRhIHN1YnNldHMgdGhhdCB3ZSB1c2VkIGZvciBjcm9zcyB2YWxpZGF0aW9uLiBBZnRlciB3ZSB0ZXN0ZWQgc2V2ZXJhbCBkaWZmZXJlbnQgbWV0aG9kcyB0byBtb2RlbCBvdXIgZGF0YSwgd2UgY29tcGFyZWQgdGhlbSB0byBjaG9vc2UgdGhlIGJlc3QgcGVyZm9ybWluZyBtb2RlbCBhcyBvdXIgZmluYWwgbW9kZWwuICAKCjUpIE92ZXJhbGwgbW9kZWwgcGVyZm9ybWFuY2UgZXZhbHVhdGlvbiAgCgpPbmNlIHdlIGNob3NlIG91ciBmaW5hbCBtb2RlbCwgd2UgZXZhbHVhdGVkIHRoZSBmaW5hbCBtb2RlbCBwZXJmb3JtYW5jZSB1c2luZyB0aGUgdGVzdGluZyBkYXRhLiBUaGlzIGdpdmVzIHVzIGEgYmV0dGVyIGVzdGltYXRlIGFib3V0IGhvdyB3ZWxsIHRoZSBtb2RlbCB3aWxsIHByZWRpY3Qgb3IgY2xhc3NpZnkgdGhlIG91dGNvbWUgdmFyaWFibGUgb2YgaW50ZXJlc3Qgd2l0aCBuZXcgaW5kZXBlbmRlbnQgZGF0YS4gSWRlYWxseSBvbmUgd291bGQgYWxzbyBwZXJmb3JtIGFuIGV2YWx1YXRpb24gd2l0aCBpbmRlcGVuZGVudCBkYXRhIHRvIHByb3ZpZGUgYSBzZW5zZSBvZiBob3cgZ2VuZXJhbGl6YWJsZSB0aGUgbW9kZWwgaXMgdG8gb3RoZXIgZGF0YSBzb3VyY2VzLiAKCldlIGZpcnN0IGZpdCBvdXIgbW9kZWwgdG8gb3VyIHRlc3RpbmcgZGF0YSB1c2luZyBlaXRoZXIganVzdCBwYXJzbmlwIGFuZCB0aGUgcHJlLXByb2Nlc3NlZCB0ZXN0aW5nIGRhdGEgKHVzaW5nIHRoZSBgYmFrZSgpYCByZWNpcGVzIGZ1bmN0aW9uKSwgb3Igb3VyIHJhdyB0ZXN0aW5nIGRhdGEgaWYgd2UgdXNlZCBhIHdvcmtmbG93LiBXZSB1c2VkIHRoZSBzYW1lIHBlcmZvcm1hbmNlIGV2YWx1YXRpb24gZnVuY3Rpb25zIChgeWFyZHN0aWNrOjptZXRyaWNzKClgICBhbmQgYHR1bmU6OmNvbGxlY3RfbWV0cmljcygpYCh3aGVuIHVzaW5nIGNyb3NzIHZhbGlkYXRpb24pKS4gV2UgYWxzbyBsZWFybmVkIGhvdyB3ZSBjYW4gdXNlIHRoZSBgbGFzdF9maXQoKWAgZnVuY3Rpb24gb2YgdGhlIGB0dW5lYCBwYWNrYWdlIGlmIHdlIHVzZWQgYSB3b3JrZmxvdyB0byBnZXQgdGhlIHRlc3QgZGF0YSBwZXJmb3JtYW5jZSB1c2luZyB0aGUgaW5pdGlhbCBkYXRhIGFuZCB0aGUgdGVzdGluZy90cmFpbmluZyBzcGxpdCBpbmZvcm1hdGlvbi4KCkFuYWx5c2VzIGxpa2UgdGhlIG9uZSBpbiBvdXIgY2FzZSBzdHVkeSBhcmUgaW1wb3J0YW50IGZvciBkZWZpbmluZyB3aGljaCBncm91cHMgY291bGQgYmVuZWZpdCB0aGUgbW9zdCBmcm9tIGludGVydmVudGlvbnMsIGVkdWNhdGlvbiwgYW5kIHBvbGljeSBjaGFuZ2VzIHdoZW4gYXR0ZW1wdGluZyB0byBtaXRpZ2F0ZSBwdWJsaWMgaGVhbHRoIGNoYWxsZW5nZXMuIFlvdSBjYW4gc2VlIGluIHRoaXMgW2FydGljbGVdKGh0dHBzOi8vd3d3Lm5lam0ub3JnL2RvaS9mdWxsLzEwLjEwNTYvTkVKTW9hMTcwMjc0Nyl7dGFyZ2V0PSJfYmxhbmsifSB0aGF0IG1hbnkgYWRkaXRpb25hbCBjb25zaWRlcmF0aW9ucyB3b3VsZCBiZSBpbnZvbHZlZCB0byBhZGVxdWF0ZWx5IHVuZGVyc3RhbmQgdGhlIGRhdGEgZW5vdWdoIHRvIHJlY29tbWVuZCBwb2xpY3kgY2hhbmdlcy4KCiMjIyBTdWdnZXN0ZWQgSG9tZXdvcmsKClN0dWRlbnRzIGNhbiBwcmVkaWN0IGFpciBwb2xsdXRpb24gbW9uaXRvciB2YWx1ZXMgdXNpbmcgYSBkaWZmZXJlbnQgYWxnb3JpdGhtIGFuZCBwcm92aWRlIGFuIGV4cGxhbmF0aW9uIGZvciBob3cgdGhhdCBhbGdvcml0aG0gd29ya3MgYW5kIHdoeSBpdCBtYXkgYmUgYSBnb29kIGNob2ljZSBmb3IgbW9kZWxpbmcgdGhpcyBkYXRhLgoKIyMjIEhlbHBmdWwgTGlua3MKCjEpIEEgcmV2aWV3IG9mIFt0aWR5bW9kZWxzXShodHRwczovL3J2aWV3cy5yc3R1ZGlvLmNvbS8yMDE5LzA2LzE5L2EtZ2VudGxlLWludHJvLXRvLXRpZHltb2RlbHMvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKMikgQSBbY291cnNlIG9uIHRpZHltb2RlbHNdKGh0dHBzOi8vanVsaWFzaWxnZS5jb20vYmxvZy90aWR5bW9kZWxzLW1sLWNvdXJzZS8pe3RhcmdldD0iX2JsYW5rIn0gYnkgSnVsaWEgU2lsZ2UgIAozKSBbTW9yZSBleGFtcGxlcywgZXhwbGFuYXRpb25zLCBhbmQgaW5mbyBhYm91dCB0aWR5bW9kZWxzIGRldmVsb3BtZW50XShodHRwczovL3d3dy50aWR5bW9kZWxzLm9yZy9sZWFybi8pe3RhcmdldD0iX2JsYW5rIn0gZnJvbSB0aGUgZGV2ZWxvcGVycyAgCjQpIEEgZ3VpZGUgZm9yIFtwcmVwcm9jZXNzaW5nIHdpdGggcmVjaXBlc10oaHR0cDovL3d3dy5yZWJlY2NhYmFydGVyLmNvbS9ibG9nLzIwMTktMDYtMDZfcHJlX3Byb2Nlc3NpbmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAKNSkgQSBbZ3VpZGVdKGh0dHBzOi8vYnJpYXR0ZS5naXRodWIuaW8vZ2djb3JyLyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgdXNpbmcgR0dhbGx5IHRvIGNyZWF0ZSBjb3JyZWxhdGlvbiBwbG90cyAgCjYpIEEgW2d1aWRlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnL2Jsb2cvMjAxOC8xMS9wYXJzbmlwLTAtMC0xLyl7dGFyZ2V0PSJfYmxhbmsifSBmb3IgdXNpbmcgcGFyc25pcCB0byB0cnkgZGlmZmVyZW50IGFsZ29yaXRobXMgb3IgZW5naW5lcyAgCjcpIEEgW2xpc3Qgb2YgcmVjaXBlIGZ1bmN0aW9uc10oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby9yZWNpcGVzL3JlZmVyZW5jZS9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAKOCkgQSBncmVhdCBibG9nIHBvc3QgYWJvdXQgW2Nyb3NzIHZhbGlkYXRpb25dKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS90cmFpbi10ZXN0LXNwbGl0LWFuZC1jcm9zcy12YWxpZGF0aW9uLWluLXB5dGhvbi04MGI2MWJlY2E0YjYpe3RhcmdldD0iX2JsYW5rIn0gIAo5KSBBIGRpc2N1c3Npb24gYWJvdXQgW2V2YWx1YXRpbmcgbW9kZWwgcGVyZm9ybWFuY2VdKGh0dHBzOi8vbWVkaXVtLmNvbS9AbGltYXZhbGxhbnRpbi9tZXRyaWNzLXRvLW1lYXN1cmUtbWFjaGluZS1sZWFybmluZy1tb2RlbC1wZXJmb3JtYW5jZS1lOGM5NjM2NjU0NzYpe3RhcmdldD0iX2JsYW5rIn0gZm9yIGEgZGVlcGVyIGV4cGxhbmF0aW9uIGFib3V0IGhvdyB0byBldmFsdWF0ZSBtb2RlbCBwZXJmb3JtYW5jZSAgCjEwKSBbUlN0dWRpbyBjaGVhdHNoZWV0c10oaHR0cHM6Ly9yc3R1ZGlvLmNvbS9yZXNvdXJjZXMvY2hlYXRzaGVldHMvKXt0YXJnZXQ9Il9ibGFuayJ9CjExKSBBbiBbZXhwbGFuYXRpb25dKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9zdXBlcnZpc2VkLXZzLXVuc3VwZXJ2aXNlZC1sZWFybmluZy0xNGY2OGUzMmVhOGQpe3RhcmdldD0iX2JsYW5rIn0gb2Ygc3VwZXJ2aXNlZCB2cyB1bnN1cGVydmlzZWQgbWFjaGluZSBsZWFybmluZyBhbmQgYmlhcy12YXJpYW5jZSB0cmFkZS1vZmYuCjEyKSBBIHRob3JvdWdoIFtleHBsYW5hdGlvbl0oaHR0cHM6Ly9yb3lhbHNvY2lldHlwdWJsaXNoaW5nLm9yZy9kb2kvMTAuMTA5OC9yc3RhLjIwMTUuMDIwMiM6fjp0ZXh0PVByaW5jaXBhbCUyMGNvbXBvbmVudCUyMGFuYWx5c2lzJTIwKFBDQSklMjBpcyx2YXJpYWJsZXMlMjB0aGF0JTIwc3VjY2Vzc2l2ZWx5JTIwbWF4aW1pemUlMjB2YXJpYW5jZS4pe3RhcmdldD0iX2JsYW5rIn0gb2YgcHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcy4KMTMpIElmIHlvdSBoYXZlIGFjY2VzcywgdGhpcyBpcyBhIGdyZWF0IFtkaXNjdXNzaW9uXShodHRwczovL3d3dy50YW5kZm9ubGluZS5jb20vZG9pL2Ficy8xMC4xMDgwLzAwMDMxMzA1LjE5ODQuMTA0ODMxODMpe3RhcmdldD0iX2JsYW5rIn0gIGFib3V0IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gaW5kZXBlbmRlbmNlLCBvcnRob2dvbmFsaXR5LCBhbmQgbGFjayBvZiBjb3JyZWxhdGlvbi4KMTQpIEdyZWF0IFt2aWRlbyBleHBsYW5hdGlvbl0oaHR0cHM6Ly95b3V0dS5iZS9fVVZIbmVCVUJXMCl7dGFyZ2V0PSJfYmxhbmsifSBvZiBQQ0EuICAKCjx1PlRlcm1zIGFuZCBjb25jZXB0cyBjb3ZlcmVkOjwvdT4gIApbVGlkeXZlcnNlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgCltwYXJhbWV0ZXJzIGFuZCBoeXBlci1wYXJhbWV0ZXJzXShodHRwczovL3d3dy5kYXRhY2FtcC5jb20vY29tbXVuaXR5L3R1dG9yaWFscy9wYXJhbWV0ZXItb3B0aW1pemF0aW9uLW1hY2hpbmUtbGVhcm5pbmctbW9kZWxzKXt0YXJnZXQ9Il9ibGFuayJ9ICAKCjx1PlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OiA8L3U+CgogUGFja2FnZSAgIHwgVXNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCltoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpe3RhcmdldD0iX2JsYW5rIn0gICAgICAgfCB0byBlYXNpbHkgbG9hZCBhbmQgc2F2ZSBkYXRhCltyZWFkcl0oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gaW1wb3J0IHRoZSBDU1YgZmlsZSBkYXRhCltkcGx5cl0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gdmlldy9hcnJhbmdlL2ZpbHRlci9zZWxlY3QvY29tcGFyZSBzcGVjaWZpYyBzdWJzZXRzIG9mIHRoZSBkYXRhIApbc2tpbXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9za2ltci9pbmRleC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBnZXQgYW4gb3ZlcnZpZXcgb2YgZGF0YQpbc3VtbWFyeXRvb2xzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc2tpbXIvaW5kZXguaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gZ2V0IGFuIG92ZXJ2aWV3IG9mIGRhdGEgaW4gYSBkaWZmZXJlbnQgc3R5bGUKW21hZ3JpdHRyXShodHRwczovL21hZ3JpdHRyLnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvbWFncml0dHIuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgIHwgdG8gdXNlIHRoZSBgJTw+JWAgcGlwcGluZyBvcGVyYXRvciAKW2NvcnJwbG90XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvY29ycnBsb3QvdmlnbmV0dGVzL2NvcnJwbG90LWludHJvLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBtYWtlIGxhcmdlIGNvcnJlbGF0aW9uIHBsb3RzCltnZ2NvcnJwbG90XShodHRwOi8vd3d3LnN0aGRhLmNvbS9lbmdsaXNoL3dpa2kvZ2djb3JycGxvdC12aXN1YWxpemF0aW9uLW9mLWEtY29ycmVsYXRpb24tbWF0cml4LXVzaW5nLWdncGxvdDIpe3RhcmdldD0iX2JsYW5rIn18IGFsc28gdG8gbWFrZSBsYXJnZSBjb3JyZWxhdGlvbiBwbG90cwpbR0dhbGx5XShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvR0dhbGx5L0dHYWxseS5wZGYpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBtYWtlIHNtYWxsZXIgY29ycmVsYXRpb24gcGxvdHMgIApbcnNhbXBsZV0oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby9yc2FtcGxlL2FydGljbGVzL0Jhc2ljcy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byBzcGxpdCB0aGUgZGF0YSBpbnRvIHRlc3RpbmcgYW5kIHRyYWluaW5nIHNldHMgYW5kIHRvIHNwbGl0IHRoZSB0cmFpbmluZyBzZXQgZm9yIGNyb3NzLXZhbGlkYXRpb24gIApbcmVjaXBlc10oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby9yZWNpcGVzLyl7dGFyZ2V0PSJfYmxhbmsifSAgIHwgdG8gcHJlLXByb2Nlc3MgZGF0YSBmb3IgbW9kZWxpbmcgaW4gYSB0aWR5IGFuZCByZXByb2R1Y2libGUgd2F5IGFuZCB0byBleHRyYWN0IHByZS1wcm9jZXNzZWQgZGF0YSAobWFqb3IgZnVuY3Rpb25zIGFyZSBgcmVjaXBlKClgICwgYHByZXAoKWAgYW5kIHZhcmlvdXMgdHJhbnNmb3JtYXRpb24gYHN0ZXBfKigpYCBmdW5jdGlvbnMsIGFzIHdlbGwgYXMgYGp1aWNlKClgIC0gZXh0cmFjdHMgZmluYWwgcHJlcHJvY2Vzc2VkIHRyYWluaW5nIGRhdGEgYW5kIGBiYWtlKClgIC0gYXBwbGllcyByZWNpcGUgc3RlcHMgdG8gdGVzdGluZyBkYXRhKS4gU2VlIFtoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcmVjaXBlcy9yZWNpcGVzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgZm9yIG1vcmUgaW5mby4KW3BhcnNuaXBdKGh0dHBzOi8vdGlkeW1vZGVscy5naXRodWIuaW8vcGFyc25pcC8pe3RhcmdldD0iX2JsYW5rIn0gICB8IGFuIGludGVyZmFjZSB0byBjcmVhdGUgbW9kZWxzIChtYWpvciBmdW5jdGlvbnMgYXJlICBgZml0KClgLCBgc2V0X2VuZ2luZSgpYCkKW3lhcmRzdGlja10oaHR0cHM6Ly90aWR5bW9kZWxzLmdpdGh1Yi5pby95YXJkc3RpY2svKXt0YXJnZXQ9Il9ibGFuayJ9ICAgfCB0byBldmFsdWF0ZSB0aGUgcGVyZm9ybWFuY2Ugb2YgbW9kZWxzClticm9vbV0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy9ibG9nLzIwMTgvMDcvYnJvb20tMC01LTAvKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gZ2V0IHRpZHkgb3V0cHV0IGZvciBvdXIgbW9kZWwgZml0IGFuZCBwZXJmb3JtYW5jZQpbZ2dwbG90Ml0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgIHwgdG8gbWFrZSB2aXN1YWxpemF0aW9ucyB3aXRoIG11bHRpcGxlIGxheWVycwpbZGlhbHNdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvYmxvZy8yMDE5LzEwL2RpYWxzLTAtMC0zLyl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIHNwZWNpZnkgaHlwZXItcGFyYW1ldGVyIHR1bmluZwpbdHVuZV0oaHR0cHM6Ly90dW5lLnRpZHltb2RlbHMub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIHBlcmZvcm0gY3Jvc3MgdmFsaWRhdGlvbiwgdHVuZSBoeXBlci1wYXJhbWV0ZXJzLCBhbmQgZ2V0IHBlcmZvcm1hbmNlIG1ldHJpY3MKW3dvcmtmbG93c10oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3dvcmtmbG93cy92ZXJzaW9ucy8wLjEuMSl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGNyZWF0ZSBtb2RlbGluZyB3b3JrZmxvdyB0byBzdHJlYW1saW5lIHRoZSBtb2RlbGluZyBwcm9jZXNzClt2aXBdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy92aXAvdmlwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGNyZWF0ZSB2YXJpYWJsZSBpbXBvcnRhbmNlIHBsb3RzCltyYW5kb21Gb3Jlc3RdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yYW5kb21Gb3Jlc3QvcmFuZG9tRm9yZXN0LnBkZil7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIHBlcmZvcm0gdGhlIHJhbmRvbSBmb3Jlc3QgYW5hbHlzaXMKW3N0cmluZ3JdKGh0dHBzOi8vc3RyaW5nci50aWR5dmVyc2Uub3JnL2FydGljbGVzL3N0cmluZ3IuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSAgICB8IHRvIG1hbmlwdWxhdGUgdGhlIHRleHQgdGhlIG1hcCBkYXRhClt0aWR5cl0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gc2VwYXJhdGUgZGF0YSB3aXRoaW4gYSBjb2x1bW4gaW50byBtdWx0aXBsZSBjb2x1bW5zCltybmF0dXJhbGVhcnRoXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcm5hdHVyYWxlYXJ0aC9SRUFETUUuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGdldCB0aGUgZ2VvbWV0cnkgZGF0YSBmb3IgdGhlIGVhcnRoIHRvIHBsb3QgdGhlIFVTClttYXBzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFwcy9tYXBzLnBkZil7dGFyZ2V0PSJfYmxhbmsifSB8IHRvIGdldCBtYXAgZGF0YWJhc2UgZGF0YSBhYm91dCBjb3VudGllcyB0byBkcmF3IHRoZW0gb24gb3VyIFVTIG1hcApbc2ZdKGh0dHBzOi8vci1zcGF0aWFsLmdpdGh1Yi5pby9zZi8pIHwgdG8gY29udmVydCB0aGUgbWFwIGRhdGEgaW50byBhIGRhdGEgZnJhbWUKW2x3Z2VvbV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2x3Z2VvbS9sd2dlb20ucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gdXNlIHRoZSBgc2ZgIGZ1bmN0aW9uIHRvIGNvbnZlcnQgdGhlIG1hcCBnZW9ncmFwaGljYWwgZGF0YQpbcmdlb3NdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9yZ2Vvcy9yZ2Vvcy5wZGYpe3RhcmdldD0iX2JsYW5rIn0gfCB0byB1c2UgZ2VvbWV0cnkgZGF0YQpbY293cGxvdF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2Nvd3Bsb3QvdmlnbmV0dGVzL2ludHJvZHVjdGlvbi5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9IHwgdG8gYWxsb3cgcGxvdHMgdG8gYmUgY29tYmluZWQKCiMjIFNlc3Npb24gaW5mbwoqKioKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoKCg==